/**
 * KI-Shield Platzhalter — Lizenz-Client.
 *
 * Holt beim Lizenz-Server (Zero-Knowledge, sieht nie Chat-Daten) ein
 * kurzlebiges, Ed25519-signiertes Token und verifiziert es im Browser mit dem
 * eingebauten Public Key. Ohne gültiges Token schaltet das Plugin fail-closed ab.
 *
 * Gespeichert wird in api.storage.local:
 *   kishield_license_key    — der hinterlegte Lizenz-Key
 *   kishield_license_token  — das signierte Token
 *   kishield_license_meta   — {org_name, valid_until} für die Anzeige
 *   kishield_device_id      — anonyme Geräte-ID (für das Aktivierungslimit)
 */

const LICENSE_API = 'https://kishieldguard.de/license/validate';
// Ed25519 Public Key des Servers (Raw, base64). Nur zum VERIFIZIEREN — kann keine
// Tokens fälschen. Muss zum Signing-Key im Server-Volume passen.
const PUBLIC_KEY_B64 = 'LMwRCfVEP2xaleNdNK+dtzkCVEW8lD1HV7kv388tR1Y=';

// Reaktiviere automatisch, wenn das Token weniger als so lange gültig ist.
const REFRESH_BEFORE_MS = 24 * 3600 * 1000; // 1 Tag

// Cross-Browser: Firefox liefert Promises zuverlässig über browser.*, Chrome über
// chrome.* (MV3). Diese Normalisierung stellt sicher, dass await/then in beiden
// Browsern funktioniert — sonst bräche in Firefox die fail-closed-Lizenzprüfung
// (chrome.* callback-only → undefined → Fehler → alles gesperrt).
const api = (typeof browser !== 'undefined' && browser.storage) ? browser : chrome;

function _b64ToBytes(b64) {
  const bin = atob(b64);
  const out = new Uint8Array(bin.length);
  for (let i = 0; i < bin.length; i++) out[i] = bin.charCodeAt(i);
  return out;
}
function _b64urlToBytes(s) {
  s = s.replace(/-/g, '+').replace(/_/g, '/');
  while (s.length % 4) s += '=';
  return _b64ToBytes(s);
}

let _pubKeyPromise = null;
function _getPubKey() {
  if (!_pubKeyPromise) {
    _pubKeyPromise = crypto.subtle.importKey(
      'raw', _b64ToBytes(PUBLIC_KEY_B64), { name: 'Ed25519' }, false, ['verify']
    );
  }
  return _pubKeyPromise;
}

async function _get(keys) {
  try { return await api.storage.local.get(keys); } catch (_) { return {}; }
}
async function _set(obj) {
  try { await api.storage.local.set(obj); } catch (_) {}
}

export async function getDeviceId() {
  const r = await _get('kishield_device_id');
  if (r && r.kishield_device_id) return r.kishield_device_id;
  const id = (crypto.randomUUID && crypto.randomUUID()) ||
    ([...crypto.getRandomValues(new Uint8Array(16))].map((b) => b.toString(16).padStart(2, '0')).join(''));
  await _set({ kishield_device_id: id });
  return id;
}

/** Verifiziert Signatur + Ablauf. Gibt das Payload-Objekt zurück oder null. */
export async function verifyToken(token) {
  try {
    if (!token || token.indexOf('.') < 0) return null;
    const [payloadB64, sigB64] = token.split('.');
    const payloadBytes = _b64urlToBytes(payloadB64);
    const sigBytes = _b64urlToBytes(sigB64);
    const pub = await _getPubKey();
    const ok = await crypto.subtle.verify({ name: 'Ed25519' }, pub, sigBytes, payloadBytes);
    if (!ok) return null;
    const payload = JSON.parse(new TextDecoder().decode(payloadBytes));
    if (!payload.exp || payload.exp * 1000 <= Date.now()) return null; // abgelaufen
    return payload;
  } catch (_) {
    return null;
  }
}

/**
 * Aktueller Lizenz-Status (offline, ohne Server).
 * → { status: 'active'|'expired'|'none', key, org_name, valid_until, exp }
 */
export async function getLicenseState() {
  const r = await _get(['kishield_license_key', 'kishield_license_token', 'kishield_license_meta']);
  const key = r.kishield_license_key || null;
  const meta = r.kishield_license_meta || {};
  if (!key) return { status: 'none' };
  const payload = await verifyToken(r.kishield_license_token);
  if (payload) {
    return { status: 'active', key, org_name: meta.org_name, valid_until: meta.valid_until, exp: payload.exp };
  }
  return { status: 'expired', key, org_name: meta.org_name, valid_until: meta.valid_until };
}

/** Fragt den Server: Key gültig? Speichert Token bei Erfolg. Gibt das Server-Ergebnis zurück. */
export async function activate(key) {
  const device_id = await getDeviceId();
  let res;
  try {
    const resp = await fetch(LICENSE_API, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json' },
      body: JSON.stringify({ key: key.trim().toUpperCase(), device_id }),
    });
    res = await resp.json();
  } catch (e) {
    return { valid: false, reason: 'offline', offline: true };
  }
  if (res && res.valid && res.token) {
    // Token lokal gegen unseren Public Key gegenprüfen (Server-unabhängige Sicherheit).
    const payload = await verifyToken(res.token);
    if (!payload) return { valid: false, reason: 'bad_signature' };
    await _set({
      kishield_license_key: key.trim().toUpperCase(),
      kishield_license_token: res.token,
      kishield_license_meta: { org_name: res.org_name, valid_until: res.valid_until },
    });
  } else if (res && !res.valid && !res.offline) {
    // Server ist erreichbar und lehnt DEFINITIV ab (gesperrt/abgelaufen/revoked):
    // gespeichertes Token SOFORT entfernen → Kill-Switch wirkt sofort, nicht erst nach
    // Token-Ablauf. Der Key bleibt hinterlegt, damit nach Freischaltung neu aktiviert
    // werden kann. Bei 'offline' bleibt das alte Token gültig (Offline-Toleranz).
    try { await api.storage.local.remove('kishield_license_token'); } catch (_) {}
    if (key) await _set({ kishield_license_key: key.trim().toUpperCase() });
  }
  return res;
}

/** Reaktivierung mit dem bereits hinterlegten Key. */
export async function reactivate() {
  const r = await _get('kishield_license_key');
  if (!r || !r.kishield_license_key) return { valid: false, reason: 'no_key' };
  return activate(r.kishield_license_key);
}

/** Entfernt die Lizenz vom Gerät. */
export async function deactivate() {
  try {
    await api.storage.local.remove(['kishield_license_key', 'kishield_license_token', 'kishield_license_meta']);
  } catch (_) {}
}

/**
 * Sorgt beim Start für einen frischen Zustand: ist das Token abgelaufen oder läuft
 * es bald ab, wird im Hintergrund automatisch reaktiviert (wenn online). Gibt den
 * (ggf. aktualisierten) Status zurück.
 */
export async function ensureFresh() {
  const state = await getLicenseState();
  if (state.status === 'none') return state;
  const soon = state.status === 'expired' ||
    (state.exp && state.exp * 1000 - Date.now() < REFRESH_BEFORE_MS);
  if (soon) {
    await reactivate().catch(() => {});
    return getLicenseState();
  }
  return state;
}
