/**
 * ChiliColectivo Mic – Lizenz & Trial
 * Wird in background (importScripts), options und content geladen.
 */
(function (global) {
  const CHILLICOLLECTIVO_LICENSE = {
    API_BASE: 'http://www.chili-voice.de/portal',
    SALES_URL: 'http://www.chili-voice.de',
    PORTAL_SETTINGS_URL: 'http://www.chili-voice.de/portal/62941853/settings.php',
    STORAGE_KEY: 'chillicollectivoLicense',
    DEVICE_ID_KEY: 'chillicollectivoDeviceId',
    TRIAL_STARTED_KEY: 'chillicollectivoTrialStartedAt',
    FORCE_LOCK_KEY: 'chillicollectivoLicenseForceLocked',
    ACTIVATING_KEY: 'chillicollectivoLicenseActivating',
    TRIAL_COOKIE_NAME: 'chillicollectivo_trial_started',
    TRIAL_CONSUMED_COOKIE_NAME: 'chillicollectivo_trial_consumed',
    LICENSE_COOKIE_NAME: 'chillicollectivo_license_key',
    LICENSE_COOKIE_MAX_AGE_DAYS: 365,
    TRIAL_COOKIE_RETENTION_DAYS: 365,
    TRIAL_CONSUMED_KEY: 'chillicollectivoTrialConsumed',
    TRIAL_COOKIE_URLS: [
      'http://www.chili-voice.de/',
      'http://chili-voice.de/',
    ],
    OUT_COUNTER_TOTAL_KEY: 'chillicollectivoOutCounterTotal',
    OUT_REWARD_KEY: 'chillicollectivoOutReward',
    OUT_REWARD_MILESTONE: 25000,
    OUT_REWARD_MAX_CLAIMS: 2,
    OUT_REWARD_MONTH_MS: 30 * 24 * 60 * 60 * 1000,
    MONTH_MS: 30 * 24 * 60 * 60 * 1000,
    YEAR_MS: 365 * 24 * 60 * 60 * 1000,
    TRIAL_MS: 1 * 60 * 1000,
    REVALIDATE_MS: 6 * 60 * 60 * 1000,
    OFFLINE_GRACE_MS: 24 * 60 * 60 * 1000,
    FEATURES_STORAGE_KEY: 'chillicollectivoLicenseFeatures',
    CHILI_STIMMUNG_ENABLED_KEY: 'chillicollectivoChiliStimmungEnabled',
    HIDDEN_SECTION_UNLOCKED_KEY: 'chillicollectivoHiddenSectionUnlocked',
    LOCAL_LICENSES_URL: 'licenses-local.json',
    MIC_UPDATE_STORAGE_KEY: 'chillicollectivoMicUpdate',
    LICENSE_REVALIDATE_ALARM: 'chillicollectivoLicenseRevalidate',
    /** false = 1-Minuten-Test (testweise), danach nur mit Lizenzschlüssel. */
  };

  /** Kein öffentlicher Demo-Schlüssel mehr – nur licenses-local.json / Server. */
  const CHILLICOLLECTIVO_OFFLINE_LICENSE_FALLBACK = [];

  function chillicollectivoGetExtensionVersion() {
    try {
      const version = chrome?.runtime?.getManifest?.()?.version;
      return String(version || '0.0.0').trim() || '0.0.0';
    } catch (_) {
      return '0.0.0';
    }
  }

  function chillicollectivoNormalizeChiliVoiceHttpUrl(url) {
    const raw = String(url || '').trim();
    if (!raw) return '';
    return raw.replace(/^https:\/\/(www\.)?chili-voice\.de/i, 'http://$1chili-voice.de');
  }

  async function chillicollectivoStoreMicUpdateInfo(micUpdate) {
    if (!micUpdate || typeof micUpdate !== 'object') return;
    const downloads = Array.isArray(micUpdate.downloads)
      ? micUpdate.downloads.map((entry) => ({
        ...entry,
        url: chillicollectivoNormalizeChiliVoiceHttpUrl(entry?.url),
      })).filter((entry) => entry?.url)
      : [];
    await chillicollectivoLicenseStorageSet({
      [CHILLICOLLECTIVO_LICENSE.MIC_UPDATE_STORAGE_KEY]: {
        current: micUpdate.current || chillicollectivoGetExtensionVersion(),
        latest: micUpdate.latest || null,
        min: micUpdate.min || null,
        outdated: !!micUpdate.outdated,
        updateRequired: !!micUpdate.updateRequired,
        message: micUpdate.message || '',
        downloadHint: micUpdate.downloadHint || '',
        downloadUrl: chillicollectivoNormalizeChiliVoiceHttpUrl(micUpdate.downloadUrl),
        downloads,
        checkedAt: Date.now(),
      },
    });
  }

  async function chillicollectivoGetMicUpdateInfo() {
    const data = await chillicollectivoLicenseStorageGet([CHILLICOLLECTIVO_LICENSE.MIC_UPDATE_STORAGE_KEY]);
    return data[CHILLICOLLECTIVO_LICENSE.MIC_UPDATE_STORAGE_KEY] || null;
  }

  async function chillicollectivoFetchMicUpdateFromServer() {
    const extensionVersion = chillicollectivoGetExtensionVersion();
    const url = `${CHILLICOLLECTIVO_LICENSE.API_BASE}/api/mic-update.php?version=${encodeURIComponent(extensionVersion)}`;
    try {
      const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
      const timeoutId = controller ? setTimeout(() => controller.abort(), 8000) : null;
      const response = await fetch(url, { method: 'GET', cache: 'no-store', signal: controller?.signal });
      if (timeoutId) clearTimeout(timeoutId);
      const payload = await response.json().catch(() => ({}));
      const micUpdate = payload?.micUpdate && typeof payload.micUpdate === 'object'
        ? payload.micUpdate
        : null;
      if (micUpdate) {
        await chillicollectivoStoreMicUpdateInfo(micUpdate);
        return chillicollectivoGetMicUpdateInfo();
      }
    } catch (_) {}
    return chillicollectivoGetMicUpdateInfo();
  }

  function chillicollectivoResolveMicUpdateDownloads(info) {
    if (Array.isArray(info?.downloads) && info.downloads.length) {
      return info.downloads
        .map((entry) => ({
          ...entry,
          url: chillicollectivoNormalizeChiliVoiceHttpUrl(entry?.url),
        }))
        .filter((entry) => entry?.url);
    }
    const downloadUrl = chillicollectivoNormalizeChiliVoiceHttpUrl(info?.downloadUrl);
    if (downloadUrl) {
      return [{
        version: info.latest || '',
        url: downloadUrl,
        role: 'latest',
        label: 'Neueste Version',
      }];
    }
    return [];
  }

  function chillicollectivoOpenMicUpdateDownload(info, urlOverride = '') {
    const url = chillicollectivoNormalizeChiliVoiceHttpUrl(
      String(urlOverride || info?.downloadUrl || '').trim(),
    );
    if (!url) return false;
    if (typeof chrome !== 'undefined' && chrome.tabs?.create) {
      chrome.tabs.create({ url, active: true });
      return true;
    }
    if (typeof global.open === 'function') {
      global.open(url, '_blank', 'noopener');
      return true;
    }
    return false;
  }

  function chillicollectivoMergeOfflineLicenseLists(...lists) {
    const byKey = new Map();
    for (const list of lists) {
      for (const entry of list || []) {
        const normalized = chillicollectivoNormalizeLicenseKey(entry?.key);
        if (normalized) byKey.set(normalized, { ...entry, key: normalized });
      }
    }
    return [...byKey.values()];
  }

  let chillicollectivoOfflineLicenseCache = null;
  let chillicollectivoOfflineLicenseLoadPromise = null;

  async function chillicollectivoLoadOfflineLicenses(force = false) {
    if (!force && chillicollectivoOfflineLicenseCache) {
      return chillicollectivoOfflineLicenseCache;
    }
    if (!force && chillicollectivoOfflineLicenseLoadPromise) {
      return chillicollectivoOfflineLicenseLoadPromise;
    }

    chillicollectivoOfflineLicenseLoadPromise = (async () => {
      let loaded = [];

      if (Array.isArray(global.CHILLICOLLECTIVO_OFFLINE_LICENSES)) {
        loaded = global.CHILLICOLLECTIVO_OFFLINE_LICENSES.slice();
      } else {
        const urls = [];
        if (typeof chrome !== 'undefined' && chrome.runtime?.getURL) {
          urls.push(chrome.runtime.getURL(CHILLICOLLECTIVO_LICENSE.LOCAL_LICENSES_URL));
        }
        urls.push(CHILLICOLLECTIVO_LICENSE.LOCAL_LICENSES_URL);

        for (const url of urls) {
          try {
            const response = await fetch(url, { cache: 'no-store' });
            if (!response.ok) continue;
            const data = await response.json();
            if (Array.isArray(data)) {
              loaded = data;
              break;
            }
          } catch (_) {}
        }
      }

      chillicollectivoOfflineLicenseCache = chillicollectivoMergeOfflineLicenseLists(
        loaded,
        CHILLICOLLECTIVO_OFFLINE_LICENSE_FALLBACK
      );
      return chillicollectivoOfflineLicenseCache;
    })();

    try {
      return await chillicollectivoOfflineLicenseLoadPromise;
    } finally {
      chillicollectivoOfflineLicenseLoadPromise = null;
    }
  }

  function chillicollectivoFindOfflineLicenseEntry(entries, normalizedKey) {
    return (entries || []).find(
      (entry) => chillicollectivoNormalizeLicenseKey(entry?.key) === normalizedKey
    ) || null;
  }

  function chillicollectivoBuildLocalLicensePayload(entry, normalizedKey) {
    const expiresAt = entry?.expiresAt ? Date.parse(entry.expiresAt) : null;
    const expired = expiresAt && expiresAt < Date.now();
    const revoked = entry?.status === 'revoked';
    const active = entry?.status === 'active' && !expired && !revoked;

    return {
      valid: active,
      key: normalizedKey,
      email: entry?.email || null,
      plan: entry?.plan || 'monthly',
      status: expired ? 'expired' : (entry?.status || 'active'),
      expiresAt: expiresAt || null,
      features: entry?.features && typeof entry.features === 'object' ? entry.features : {},
      message: active
        ? 'Lizenz gültig (Offline-Modus)'
        : expired
          ? 'Lizenz abgelaufen.'
          : revoked
            ? 'Lizenz gesperrt.'
            : 'Lizenz ungültig.',
    };
  }

  async function chillicollectivoValidateLicenseKeyLocally(key) {
    const normalized = chillicollectivoNormalizeLicenseKey(key);
    if (!normalized || normalized.length < 10) return null;

    const entries = await chillicollectivoLoadOfflineLicenses();
    const entry = chillicollectivoFindOfflineLicenseEntry(entries, normalized);
    if (!entry) return null;

    const payload = chillicollectivoBuildLocalLicensePayload(entry, normalized);
    if (!payload.valid) {
      throw new Error(payload.message || 'Lizenz ungültig oder gesperrt.');
    }

    const now = Date.now();
    const license = {
      key: normalized,
      valid: true,
      validatedAt: now,
      lastError: null,
      email: payload.email,
      plan: payload.plan,
      expiresAt: payload.expiresAt,
      status: payload.status,
      features: payload.features,
      source: 'local_offline',
    };
    await chillicollectivoLicenseStorageSet({ [CHILLICOLLECTIVO_LICENSE.STORAGE_KEY]: license });
    await chillicollectivoSyncLicenseFeaturesCache(license);
    await chillicollectivoPersistActivatedLicense(license);
    return license;
  }

  async function chillicollectivoTryRefreshLocalLicense(key, options = {}) {
    try {
      return await chillicollectivoValidateLicenseKeyLocally(key);
    } catch (err) {
      if (options.silent) return null;
      throw err;
    }
  }

  function chillicollectivoGetPreviewLicenseState() {
    return {
      access: 'granted',
      reason: 'preview',
      message: 'Vorversion – Mic freigeschaltet (Lizenz folgt in der nächsten Version)',
      license: null,
      trialRemainingMs: 0,
      licenseRemainingMs: 0,
      features: { chiliStimmung: false },
    };
  }

  function chillicollectivoLicenseStorageGet(keys) {
    return new Promise((resolve) => {
      if (typeof chrome === 'undefined' || !chrome.storage?.local) {
        resolve({});
        return;
      }
      chrome.storage.local.get(keys, (data) => resolve(data || {}));
    });
  }

  function chillicollectivoLicenseStorageSet(obj) {
    return new Promise((resolve) => {
      if (typeof chrome === 'undefined' || !chrome.storage?.local) {
        resolve();
        return;
      }
      chrome.storage.local.set(obj, () => resolve());
    });
  }

  function chillicollectivoLicenseStorageRemove(keys) {
    return new Promise((resolve) => {
      if (typeof chrome === 'undefined' || !chrome.storage?.local) {
        resolve();
        return;
      }
      chrome.storage.local.remove(keys, () => resolve());
    });
  }

  async function chillicollectivoGetOrCreateDeviceId() {
    const data = await chillicollectivoLicenseStorageGet([CHILLICOLLECTIVO_LICENSE.DEVICE_ID_KEY]);
    let id = String(data[CHILLICOLLECTIVO_LICENSE.DEVICE_ID_KEY] || '').trim();
    if (id.length >= 12) return id;
    if (typeof crypto !== 'undefined' && typeof crypto.randomUUID === 'function') {
      id = `cmic-${crypto.randomUUID()}`;
    } else {
      id = `cmic-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 10)}`;
    }
    await chillicollectivoLicenseStorageSet({ [CHILLICOLLECTIVO_LICENSE.DEVICE_ID_KEY]: id });
    return id;
  }

  function chillicollectivoNormalizeLicenseKey(raw) {
    let clean = String(raw || '').trim().toUpperCase().replace(/[^A-Z0-9]/g, '');
    if (clean.startsWith('CMIC')) clean = clean.slice(4);
    const parts = clean.match(/.{1,4}/g) || [];
    if (!parts.length) return '';
    return `CMIC-${parts.slice(0, 4).join('-')}`;
  }

  function chillicollectivoFormatLicenseKeyInput(raw) {
    const clean = String(raw || '').toUpperCase().replace(/[^A-Z0-9]/g, '');
    const body = clean.startsWith('CMIC') ? clean.slice(4) : clean;
    const parts = body.match(/.{1,4}/g) || [];
    if (!parts.length) return '';
    return ['CMIC', ...parts.slice(0, 4)].join('-');
  }

  function chillicollectivoMsUntilTrialEnd(startedAt) {
    const start = Number(startedAt);
    if (!Number.isFinite(start) || start <= 0) return 0;
    const end = start + CHILLICOLLECTIVO_LICENSE.TRIAL_MS;
    return Math.max(0, end - Date.now());
  }

  function chillicollectivoFormatTrialCountdown(ms) {
    if (ms <= 0) return '0:00';
    const totalSec = Math.max(0, Math.ceil(ms / 1000));
    const min = Math.floor(totalSec / 60);
    const sec = totalSec % 60;
    return `${min}:${String(sec).padStart(2, '0')}`;
  }

  function chillicollectivoFormatTrialRemaining(ms) {
    if (ms <= 0) return 'abgelaufen';
    if (ms < 60 * 60 * 1000) {
      return chillicollectivoFormatTrialCountdown(ms);
    }
    const hours = Math.ceil(ms / (60 * 60 * 1000));
    if (hours >= 48) return `${Math.ceil(hours / 24)} Tage`;
    if (hours > 1) return `${hours} Stunden`;
    return 'unter 1 Stunde';
  }

  function chillicollectivoLicensePlanLabel(plan) {
    const p = String(plan || '').toLowerCase();
    if (p === 'monthly') return 'Monatslizenz';
    if (p === 'yearly' || p === 'lifetime') return 'Jahreslizenz';
    if (p === 'trial' || p === 'trial_5min') return 'Testlizenz';
    if (p === 'out_reward') return 'Out-Bonus';
    if (p === 'manual') return 'Monatslizenz';
    if (p === 'standard') return 'Lizenz';
    return 'Lizenz';
  }

  function chillicollectivoPlanPeriodMs(plan) {
    const p = String(plan || '').toLowerCase();
    if (p === 'trial' || p === 'trial_5min') return 5 * 60 * 1000;
    if (p === 'yearly' || p === 'lifetime') return CHILLICOLLECTIVO_LICENSE.YEAR_MS;
    if (p === 'monthly' || p === 'manual' || p === 'standard') return CHILLICOLLECTIVO_LICENSE.MONTH_MS;
    return CHILLICOLLECTIVO_LICENSE.MONTH_MS;
  }

  function chillicollectivoNormalizeExpiryMs(raw) {
    const n = Number(raw);
    if (!Number.isFinite(n) || n <= 0) return null;
    return n < 1e12 ? n * 1000 : n;
  }

  function chillicollectivoResolveLicenseExpiryMs(license, anchorMs = null) {
    const explicit = chillicollectivoNormalizeExpiryMs(license?.expiresAt);
    if (explicit != null) {
      return explicit;
    }
    const anchor = Number(anchorMs ?? license?.validatedAt ?? license?.createdAt ?? 0);
    if (!Number.isFinite(anchor) || anchor <= 0) return null;
    return anchor + chillicollectivoPlanPeriodMs(license?.plan);
  }

  function chillicollectivoLicenseExplicitlyDenied(license) {
    if (!license) return false;
    if (license.status === 'expired' || license.status === 'revoked' || license.status === 'deleted') return true;
    const err = String(license.lastError || '').toLowerCase();
    return /abgelaufen|gesperrt|unbekannt|expired|revoked|ungültig|ungueltig|not_found|invalid|gelöscht|geloescht|deleted/.test(err);
  }

  function chillicollectivoHttpLicenseErrorMessage(status) {
    const code = Number(status);
    if (!Number.isFinite(code) || code <= 0) return null;
    if (code === 404) return 'Lizenz unbekannt.';
    if (code >= 500) return 'Lizenzserver vorübergehend nicht erreichbar – bitte erneut versuchen.';
    return null;
  }

  function chillicollectivoIsGenericHttpError(message) {
    return /^HTTP \d{3}$/.test(String(message || '').trim());
  }

  function chillicollectivoIsStrictServerLicenseMode() {
    try {
      if (typeof importScripts === 'function') return true;
    } catch (_) {}
    return !!globalThis.__CHILLICOLLECTIVO_AGENTEN_MIC;
  }

  function chillicollectivoEffectiveRevalidateMs() {
    return chillicollectivoIsStrictServerLicenseMode()
      ? 5 * 60 * 1000
      : CHILLICOLLECTIVO_LICENSE.REVALIDATE_MS;
  }

  function chillicollectivoEffectiveOfflineGraceMs() {
    return chillicollectivoIsStrictServerLicenseMode()
      ? 0
      : CHILLICOLLECTIVO_LICENSE.OFFLINE_GRACE_MS;
  }

  function chillicollectivoIsServerExplicitDenial(payload, response) {
    const error = String(payload?.error || '').toLowerCase();
    const status = String(payload?.status || '').toLowerCase();
    const message = String(payload?.message || '').toLowerCase();
    if (error === 'not_found' || error === 'revoked' || error === 'deleted' || status === 'revoked' || status === 'deleted') return true;
    if (Number(response?.status) === 404) return true;
    return /unbekannt|gesperrt|revoked|not_found|gelöscht|geloescht|deleted|ungültig|ungueltig/.test(message);
  }

  function chillicollectivoIsBackgroundContext() {
    try {
      return typeof importScripts === 'function';
    } catch (_) {
      return false;
    }
  }

  async function chillicollectivoPostLicenseApi(body, options = {}) {
    const payloadBody = { ...(body || {}) };
    const timeoutMs = Number(options.timeoutMs || 12000);
    const retries = Math.max(0, Number(options.retries ?? 1));

    async function fetchOnce() {
      const controller = typeof AbortController !== 'undefined' ? new AbortController() : null;
      const timeoutId = controller ? setTimeout(() => controller.abort(), timeoutMs) : null;
      try {
        const url = `${CHILLICOLLECTIVO_LICENSE.API_BASE}/api/license.php`;
        const response = await fetch(url, {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify(payloadBody),
          cache: 'no-store',
          signal: controller?.signal,
        });
        if (timeoutId) clearTimeout(timeoutId);
        let payload = {};
        try {
          payload = await response.json();
        } catch (_) {
          payload = {};
        }
        return { response, payload, networkError: false };
      } catch (err) {
        if (timeoutId) clearTimeout(timeoutId);
        return { response: null, payload: {}, networkError: true, error: err };
      }
    }

    if (!chillicollectivoIsBackgroundContext()
      && typeof chrome !== 'undefined'
      && chrome.runtime?.sendMessage) {
      const remote = await new Promise((resolve, reject) => {
        try {
          chrome.runtime.sendMessage({
            type: 'LICENSE_SERVER_POST',
            body: payloadBody,
            timeoutMs,
          }, (resp) => {
            if (chrome.runtime.lastError) {
              reject(new Error(chrome.runtime.lastError.message));
              return;
            }
            resolve(resp || {});
          });
        } catch (e) {
          reject(e);
        }
      });
      if (remote?.success === false) {
        return {
          response: null,
          payload: remote.payload || {},
          networkError: !!remote.networkError,
          error: remote.error ? new Error(String(remote.error)) : null,
        };
      }
      return {
        response: {
          ok: !!remote.ok,
          status: Number(remote.status || 0),
        },
        payload: remote.payload || {},
        networkError: !!remote.networkError,
        error: null,
      };
    }

    let lastResult = null;
    for (let attempt = 0; attempt <= retries; attempt++) {
      if (attempt > 0) {
        await new Promise((resolve) => setTimeout(resolve, 350 + (attempt * 250)));
      }
      lastResult = await fetchOnce();
      if (!lastResult.networkError) return lastResult;
    }
    return lastResult;
  }

  function chillicollectivoUserFacingLicenseError(input, fallback = 'Lizenz ungültig oder gesperrt.') {
    if (!input) return fallback;
    if (typeof input === 'string') {
      if (/abgelaufen|expired/i.test(input)) return 'Lizenz abgelaufen.';
      return input.trim() || fallback;
    }
    const status = String(input.status || '').toLowerCase();
    const message = String(input.message || '').trim();
    if (status === 'expired' || /abgelaufen|expired/i.test(message)) {
      return 'Lizenz abgelaufen.';
    }
    if (status === 'device_mismatch' || /benutzung|anderen computer|device_mismatch|gebunden/i.test(message)) {
      return 'Lizenz bereits in benutzung auf einem anderen PC.';
    }
    if (status === 'deleted' || String(input.error || '').toLowerCase() === 'deleted' || /gelöscht|geloescht/i.test(message)) {
      return 'Lizenz gelöscht.';
    }
    return message || fallback;
  }

  function chillicollectivoIsLicenseExpired(license, now = Date.now()) {
    if (!license || license.valid !== true) return false;
    const expiryMs = chillicollectivoResolveLicenseExpiryMs(license);
    if (!expiryMs) return false;
    return expiryMs <= now;
  }

  function chillicollectivoOfflineGraceEligible(license, now = Date.now()) {
    if (!license?.key || license.source === 'local_offline') return false;
    if (chillicollectivoLicenseExplicitlyDenied(license)) return false;
    const lastValidAt = Number(license.validatedAt || 0);
    if (!lastValidAt) return false;
    const expiryMs = chillicollectivoResolveLicenseExpiryMs({ ...license, valid: true });
    if (!expiryMs || expiryMs <= now) return false;
    return (now - lastValidAt) < chillicollectivoEffectiveOfflineGraceMs();
  }

  async function chillicollectivoInvalidateStoredLicense(license, message, status = 'revoked') {
    const invalidated = {
      ...license,
      valid: false,
      lastError: message || 'Lizenz abgelaufen.',
      status,
    };
    await chillicollectivoLicenseStorageSet({ [CHILLICOLLECTIVO_LICENSE.STORAGE_KEY]: invalidated });
    await chillicollectivoClearLicenseCookieKey();
    return invalidated;
  }

  function chillicollectivoResolveServerLicenseExpiryMs(payload, prev, normalizedKey, now, options = {}) {
    const fromServer = chillicollectivoNormalizeExpiryMs(payload?.expiresAt);

    if (fromServer != null && fromServer > now) {
      return fromServer;
    }

    const remainingSec = Number(payload?.remainingSeconds ?? 0);
    if (Number.isFinite(remainingSec) && remainingSec > 0) {
      return now + (remainingSec * 1000);
    }

    if (fromServer != null) {
      return fromServer;
    }

    if (prev?.expiresAt && chillicollectivoNormalizeLicenseKey(prev?.key) === normalizedKey) {
      const prevExpiry = chillicollectivoNormalizeExpiryMs(prev.expiresAt);
      if (prevExpiry != null) return prevExpiry;
    }

    if (options.activate === true || payload?.valid === true) {
      const plan = payload?.plan || prev?.plan || 'standard';
      return now + chillicollectivoPlanPeriodMs(plan);
    }

    return null;
  }

  function chillicollectivoResolveStateRemainingMs(state) {
    if (!state || state.access !== 'granted') return 0;

    if (state.reason === 'trial' && state.license?.valid !== true) {
      return Math.max(0, Number(state.trialRemainingMs || state.licenseRemainingMs || 0));
    }

    if (state.license?.valid === true) {
      const expiryMs = chillicollectivoResolveLicenseExpiryMs(state.license);
      if (expiryMs) {
        return Math.max(0, expiryMs - Date.now());
      }
    }

    return Math.max(0, Number(state.licenseRemainingMs || state.trialRemainingMs || 0));
  }

  function chillicollectivoCountdownUsesClockFormat(remainingMs, state) {
    if (remainingMs < 60 * 60 * 1000) return true;
    const plan = String(state?.license?.plan || '').toLowerCase();
    return plan === 'trial' || plan === 'trial_5min' || state?.reason === 'trial';
  }

  function chillicollectivoMsUntilExpiry(expiresAt) {
    const end = Number(expiresAt);
    if (!Number.isFinite(end) || end <= 0) return null;
    return Math.max(0, end - Date.now());
  }

  function chillicollectivoFormatLicenseCountdown(ms) {
    if (ms <= 0) return '0:00';
    if (ms < 60 * 60 * 1000) {
      return chillicollectivoFormatTrialCountdown(ms);
    }
    const totalMin = Math.ceil(ms / (60 * 1000));
    const days = Math.floor(totalMin / (24 * 60));
    const hours = Math.floor((totalMin % (24 * 60)) / 60);
    const min = totalMin % 60;
    if (days > 0 && hours === 0 && min === 0) {
      return days === 1 ? '1 Tag' : `${days} Tage`;
    }
    if (days > 0) {
      const dayLabel = days === 1 ? '1 Tag' : `${days} Tage`;
      return hours > 0 ? `${dayLabel} ${hours} Std` : dayLabel;
    }
    return `${hours}:${String(min).padStart(2, '0')} Std`;
  }

  function chillicollectivoResolveLicenseCountdown(state) {
    if (!state || state.access !== 'granted') return null;

    const remainingMs = chillicollectivoResolveStateRemainingMs(state);
    if (remainingMs <= 0) return null;

    if (state.reason === 'trial' && state.license?.valid !== true) {
      return {
        label: 'Testphase endet in',
        remainingMs,
        mode: 'countdown',
        tone: 'trial',
      };
    }

    if (state.reason === 'offline_grace') {
      return {
        label: 'Offline-Modus – noch',
        remainingMs,
        mode: 'countdown',
        tone: 'active',
      };
    }

    const plan = String(state.license?.plan || '').toLowerCase();
    if (plan === 'trial' || plan === 'trial_5min') {
      return {
        label: 'Testlizenz endet in',
        remainingMs,
        mode: 'countdown',
        tone: 'trial',
      };
    }

    const planLabel = chillicollectivoLicensePlanLabel(state.license?.plan);
    return {
      label: `${planLabel} – noch`,
      remainingMs,
      mode: 'countdown',
      tone: state.reason === 'out_reward' ? 'bonus' : 'active',
    };
  }

  function chillicollectivoIsOutRewardLicenseKey(key) {
    const normalized = chillicollectivoNormalizeLicenseKey(key);
    return /^CMIC-OUTS-25K[12]-[A-Z0-9]{4}$/.test(normalized);
  }

  function chillicollectivoOutRewardMonthsForTier(tier) {
    return tier === 2 ? 2 : 1;
  }

  function chillicollectivoMakeOutRewardKeySuffix(seed) {
    const alphabet = 'ABCDEFGHJKLMNPQRSTUVWXYZ23456789';
    let hash = 0;
    const s = String(seed || 'cmic');
    for (let i = 0; i < s.length; i++) {
      hash = ((hash << 5) - hash + s.charCodeAt(i)) | 0;
    }
    let n = Math.abs(hash);
    let out = '';
    for (let i = 0; i < 4; i++) {
      out += alphabet[n % alphabet.length];
      n = Math.floor(n / alphabet.length) + (i + 1) * 19;
    }
    return out;
  }

  function chillicollectivoGenerateOutRewardKey(tier) {
    const installId = typeof chrome !== 'undefined' && chrome.runtime?.id ? chrome.runtime.id : 'local';
    const suffix = chillicollectivoMakeOutRewardKeySuffix(`${installId}-out-25k-${tier}`);
    return `CMIC-OUTS-25K${tier}-${suffix}`;
  }

  async function chillicollectivoGetOutRewardClaimsCount(record) {
    if (record?.claimsCount != null) {
      return Math.min(CHILLICOLLECTIVO_LICENSE.OUT_REWARD_MAX_CLAIMS, Number(record.claimsCount) || 0);
    }
    if (record?.tier != null) {
      return Math.min(CHILLICOLLECTIVO_LICENSE.OUT_REWARD_MAX_CLAIMS, Number(record.tier) || 0);
    }
    return record?.key ? 1 : 0;
  }

  function chillicollectivoOutRewardKeyMatchesRecord(normalizedKey, record) {
    if (!record) return false;
    const keys = Array.isArray(record.keys) ? record.keys : [];
    const all = [record.key, ...keys].filter(Boolean).map(chillicollectivoNormalizeLicenseKey);
    return all.includes(normalizedKey);
  }

  async function chillicollectivoResetOutCounterTotal() {
    await chillicollectivoLicenseStorageSet({
      [CHILLICOLLECTIVO_LICENSE.OUT_COUNTER_TOTAL_KEY]: 0,
    });
  }

  async function chillicollectivoGetOutRewardRecord() {
    const data = await chillicollectivoLicenseStorageGet([CHILLICOLLECTIVO_LICENSE.OUT_REWARD_KEY]);
    return data[CHILLICOLLECTIVO_LICENSE.OUT_REWARD_KEY] || null;
  }

  async function chillicollectivoApplyOutRewardLicense(reward) {
    const now = Date.now();
    const license = {
      key: reward.key,
      valid: true,
      validatedAt: now,
      lastError: null,
      email: null,
      plan: 'out_reward',
      expiresAt: reward.expiresAt,
      status: 'active',
      source: 'out_milestone',
      tier: reward.tier || null,
      monthsGranted: reward.monthsGranted || null,
    };
    await chillicollectivoLicenseStorageSet({
      [CHILLICOLLECTIVO_LICENSE.STORAGE_KEY]: license,
      [CHILLICOLLECTIVO_LICENSE.OUT_REWARD_KEY]: reward,
    });
    return license;
  }

  async function chillicollectivoValidateOutRewardKey(key) {
    const normalized = chillicollectivoNormalizeLicenseKey(key);
    if (!chillicollectivoIsOutRewardLicenseKey(normalized)) return null;

    const reward = await chillicollectivoGetOutRewardRecord();
    if (!chillicollectivoOutRewardKeyMatchesRecord(normalized, reward)) {
      throw new Error('Dieser Out-Bonus-Schlüssel gehört nicht zu dieser Installation.');
    }

    const now = Date.now();
    if (Number(reward.expiresAt) <= now) {
      throw new Error('Out-Bonus abgelaufen – Gratiszeit ist vorbei.');
    }

    return chillicollectivoApplyOutRewardLicense(reward);
  }

  async function chillicollectivoTryGrantOutMilestoneReward(totalOuts) {
    const total = Math.max(0, Number(totalOuts) || 0);
    return { granted: false, totalOuts: total };
  }

  async function chillicollectivoSyncOutCounterTotal() {
    const data = await chillicollectivoLicenseStorageGet([
      'chillicollectivoOutCounter',
      CHILLICOLLECTIVO_LICENSE.OUT_COUNTER_TOTAL_KEY,
    ]);
    const current = Number(data.chillicollectivoOutCounter) || 0;
    const total = Number(data[CHILLICOLLECTIVO_LICENSE.OUT_COUNTER_TOTAL_KEY]) || 0;
    if (current > total) {
      await chillicollectivoLicenseStorageSet({
        [CHILLICOLLECTIVO_LICENSE.OUT_COUNTER_TOTAL_KEY]: current,
      });
      return current;
    }
    return total;
  }

  function chillicollectivoResolveLicenseFeatures(license) {
    const raw = license?.features && typeof license.features === 'object' ? license.features : {};
    return {
      chiliStimmung: raw.chiliStimmung === true,
    };
  }

  async function chillicollectivoSyncLicenseFeaturesCache(license) {
    const features = chillicollectivoResolveLicenseFeatures(license);
    await chillicollectivoLicenseStorageSet({
      [CHILLICOLLECTIVO_LICENSE.FEATURES_STORAGE_KEY]: features,
    });
    await chillicollectivoEnsureChiliStimmungDefaults();
    return features;
  }

  function chillicollectivoLicenseStateHasFeature(state, featureName) {
    return state?.features?.[featureName] === true;
  }

  async function chillicollectivoHasChiliStimmungAccess() {
    const state = await chillicollectivoGetLicenseState({ scheduleWatch: false, startTrial: false });
    return state?.access === 'granted' && chillicollectivoLicenseStateHasFeature(state, 'chiliStimmung');
  }

  async function chillicollectivoGetStoredLicenseKey() {
    const data = await chillicollectivoLicenseStorageGet([CHILLICOLLECTIVO_LICENSE.STORAGE_KEY]);
    const key = data?.[CHILLICOLLECTIVO_LICENSE.STORAGE_KEY]?.key;
    return key ? chillicollectivoNormalizeLicenseKey(key) : '';
  }

  async function chillicollectivoEnsureChiliStimmungDefaults() {
    const data = await chillicollectivoLicenseStorageGet([
      CHILLICOLLECTIVO_LICENSE.CHILI_STIMMUNG_ENABLED_KEY,
    ]);
    if (data[CHILLICOLLECTIVO_LICENSE.CHILI_STIMMUNG_ENABLED_KEY] !== false) {
      await chillicollectivoLicenseStorageSet({
        [CHILLICOLLECTIVO_LICENSE.CHILI_STIMMUNG_ENABLED_KEY]: true,
      });
    }
  }

  function chillicollectivoBuildLicenseState(license, trialStartedAt) {
    const now = Date.now();
    const trialRemainingMs = chillicollectivoMsUntilTrialEnd(trialStartedAt);

    if (license?.valid === true) {
      const expiryMs = chillicollectivoResolveLicenseExpiryMs(license);
      if (expiryMs != null && chillicollectivoIsLicenseExpired(license, now)) {
        return {
          access: 'expired',
          reason: 'expired',
          message: license.plan === 'out_reward'
            ? 'Out-Bonus abgelaufen – Gratiszeit ist vorbei.'
            : 'Lizenz abgelaufen.',
          license,
          trialRemainingMs: 0,
          licenseRemainingMs: 0,
          features: { chiliStimmung: false },
        };
      }
      if (license.plan === 'out_reward') {
        const remainingMs = expiryMs ? Math.max(0, expiryMs - now) : 0;
        const months = Number(license.monthsGranted ?? (license.tier === 2 ? 2 : 1));
        const monthLabel = months === 2 ? '2 Monate gratis' : '1 Monat gratis';
        return {
          access: 'granted',
          reason: 'out_reward',
          message: `Out-Bonus – ${monthLabel} (noch ${chillicollectivoFormatTrialRemaining(remainingMs)})`,
          license,
          trialRemainingMs: 0,
          licenseRemainingMs: remainingMs,
          features: chillicollectivoResolveLicenseFeatures(license),
        };
      }
      const remainingMs = expiryMs ? Math.max(0, expiryMs - now) : 0;
      const planLabel = chillicollectivoLicensePlanLabel(license.plan);
      const reason = license.source === 'local_offline' ? 'local_offline' : 'licensed';
      let message = license.source === 'local_offline'
        ? 'Lizenz aktiv (Offline-Modus – kein Server nötig)'
        : 'Lizenz aktiv';
      if (remainingMs > 0) {
        message = `${planLabel} – noch ${chillicollectivoFormatTrialRemaining(remainingMs)}`;
      } else if (license.source === 'server') {
        message = 'Lizenz aktiv';
      }
      return {
        access: 'granted',
        reason,
        message,
        license,
        trialRemainingMs: 0,
        licenseRemainingMs: remainingMs,
        features: chillicollectivoResolveLicenseFeatures(license),
      };
    }

    if (trialRemainingMs > 0) {
      return {
        access: 'granted',
        reason: 'trial',
        message: `Testphase – noch ${chillicollectivoFormatTrialRemaining(trialRemainingMs)}`,
        license: license || null,
        trialRemainingMs,
        licenseRemainingMs: trialRemainingMs,
        features: chillicollectivoResolveLicenseFeatures(license),
      };
    }

    if (chillicollectivoOfflineGraceEligible(license, now)) {
      const graceRemainingMs = Math.max(0, chillicollectivoEffectiveOfflineGraceMs() - (now - Number(license.validatedAt || 0)));
      return {
        access: 'granted',
        reason: 'offline_grace',
        message: `Offline-Modus – noch ${chillicollectivoFormatTrialRemaining(graceRemainingMs)}`,
        license,
        trialRemainingMs: 0,
        licenseRemainingMs: graceRemainingMs,
        features: chillicollectivoResolveLicenseFeatures(license),
      };
    }

    const trialExpired = Number(trialStartedAt) > 0 && trialRemainingMs <= 0;
    return {
      access: 'denied',
      reason: trialExpired ? 'trial_expired' : (license?.key ? 'invalid' : 'no_license'),
      message: license?.lastError
        ? chillicollectivoUserFacingLicenseError(license.lastError, license?.lastError)
        : (trialExpired
          ? '1-Minuten-Test abgelaufen – Mic gesperrt. Lizenzschlüssel in den Einstellungen eingeben.'
          : 'Keine gültige Lizenz – Mic ist gesperrt.'),
      license: license || null,
      trialRemainingMs: 0,
      licenseRemainingMs: 0,
      features: { chiliStimmung: false },
    };
  }

  let chillicollectivoTrialExpiryTimer = null;
  const chillicollectivoTrialExpiredHandlers = [];

  function chillicollectivoRegisterTrialExpiredHandler(fn) {
    if (typeof fn === 'function') chillicollectivoTrialExpiredHandlers.push(fn);
  }

  function chillicollectivoCookieSecureForUrl(url) {
    return String(url || '').startsWith('https://');
  }

  async function chillicollectivoGetCookieValue(name) {
    if (typeof chrome === 'undefined' || !chrome.cookies?.get) return null;
    for (const url of CHILLICOLLECTIVO_LICENSE.TRIAL_COOKIE_URLS) {
      const cookie = await new Promise((resolve) => {
        chrome.cookies.get({ url, name }, (c) => resolve(c || null));
      });
      if (cookie?.value) return String(cookie.value);
    }
    return null;
  }

  async function chillicollectivoSetCookieValue(name, value, expirationDate) {
    if (typeof chrome === 'undefined' || !chrome.cookies?.set) return;
    for (const url of CHILLICOLLECTIVO_LICENSE.TRIAL_COOKIE_URLS) {
      await new Promise((resolve) => {
        chrome.cookies.set({
          url,
          name,
          value,
          expirationDate,
          path: '/',
          secure: chillicollectivoCookieSecureForUrl(url),
          sameSite: 'lax',
        }, () => resolve());
      });
    }
  }

  async function chillicollectivoRemoveCookie(name) {
    if (typeof chrome === 'undefined' || !chrome.cookies?.remove) return;
    for (const url of CHILLICOLLECTIVO_LICENSE.TRIAL_COOKIE_URLS) {
      await new Promise((resolve) => {
        chrome.cookies.remove({ url, name }, () => resolve());
      });
    }
  }

  async function chillicollectivoGetLicenseCookieKey() {
    const raw = await chillicollectivoGetCookieValue(CHILLICOLLECTIVO_LICENSE.LICENSE_COOKIE_NAME);
    if (!raw) return '';
    return chillicollectivoNormalizeLicenseKey(raw);
  }

  async function chillicollectivoSetLicenseCookieKey(key) {
    const normalized = chillicollectivoNormalizeLicenseKey(key);
    if (!normalized) return;
    const expirationDate = Math.floor(Date.now() / 1000)
      + (CHILLICOLLECTIVO_LICENSE.LICENSE_COOKIE_MAX_AGE_DAYS * 86400);
    await chillicollectivoSetCookieValue(
      CHILLICOLLECTIVO_LICENSE.LICENSE_COOKIE_NAME,
      normalized,
      expirationDate
    );
  }

  async function chillicollectivoClearLicenseCookieKey() {
    await chillicollectivoRemoveCookie(CHILLICOLLECTIVO_LICENSE.LICENSE_COOKIE_NAME);
  }

  async function chillicollectivoClearTrialCookie() {
    await chillicollectivoRemoveCookie(CHILLICOLLECTIVO_LICENSE.TRIAL_COOKIE_NAME);
  }

  async function chillicollectivoSuppressTrialState() {
    await chillicollectivoLicenseStorageRemove([CHILLICOLLECTIVO_LICENSE.TRIAL_STARTED_KEY]);
    await chillicollectivoClearTrialCookie();
  }

  async function chillicollectivoPersistActivatedLicense(license) {
    if (!license?.key || license.valid !== true) return;
    if (license.source === 'out_milestone' || license.plan === 'out_reward') return;
    await chillicollectivoSetLicenseCookieKey(license.key);
    await chillicollectivoSuppressTrialState();
  }

  async function chillicollectivoIsLicenseForceLocked() {
    const data = await chillicollectivoLicenseStorageGet([CHILLICOLLECTIVO_LICENSE.FORCE_LOCK_KEY]);
    return !!data[CHILLICOLLECTIVO_LICENSE.FORCE_LOCK_KEY];
  }

  async function chillicollectivoSetLicenseForceLocked(locked) {
    if (locked) {
      await chillicollectivoLicenseStorageSet({ [CHILLICOLLECTIVO_LICENSE.FORCE_LOCK_KEY]: Date.now() });
      return;
    }
    await chillicollectivoLicenseStorageRemove([CHILLICOLLECTIVO_LICENSE.FORCE_LOCK_KEY]);
  }

  async function chillicollectivoIsLicenseActivating() {
    const data = await chillicollectivoLicenseStorageGet([CHILLICOLLECTIVO_LICENSE.ACTIVATING_KEY]);
    return !!data[CHILLICOLLECTIVO_LICENSE.ACTIVATING_KEY];
  }

  async function chillicollectivoSetLicenseActivating(active) {
    if (active) {
      await chillicollectivoLicenseStorageSet({ [CHILLICOLLECTIVO_LICENSE.ACTIVATING_KEY]: Date.now() });
      return;
    }
    await chillicollectivoLicenseStorageRemove([CHILLICOLLECTIVO_LICENSE.ACTIVATING_KEY]);
  }

  async function chillicollectivoRecoverLicenseFromCookie() {
    if (await chillicollectivoIsLicenseForceLocked()) return null;
    if (await chillicollectivoIsLicenseActivating()) return null;
    const data = await chillicollectivoLicenseStorageGet([CHILLICOLLECTIVO_LICENSE.STORAGE_KEY]);
    const stored = data[CHILLICOLLECTIVO_LICENSE.STORAGE_KEY] || null;
    if (stored?.valid === true) {
      await chillicollectivoPersistActivatedLicense(stored);
      return stored;
    }

    const cookieKey = await chillicollectivoGetLicenseCookieKey();
    if (!cookieKey) return null;

    if (stored?.key && chillicollectivoNormalizeLicenseKey(stored.key) === cookieKey && stored.valid !== true) {
      const refreshed = await chillicollectivoValidateLicenseKey(cookieKey, { silent: true });
      if (refreshed?.valid) return refreshed;
    }

    if (!stored?.key || chillicollectivoNormalizeLicenseKey(stored.key) !== cookieKey) {
      const recovered = await chillicollectivoValidateLicenseKey(cookieKey, { silent: true });
      if (recovered?.valid) return recovered;
    }

    return null;
  }

  async function chillicollectivoRecoverTrialFromCookie() {
    const startedAt = await chillicollectivoResolveTrialStartedAt();
    if (startedAt) {
      await chillicollectivoPersistTrialStartedAt(startedAt);
      await chillicollectivoMarkTrialConsumed();
      return startedAt;
    }
    if (await chillicollectivoIsTrialConsumed()) {
      await chillicollectivoLicenseStorageSet({
        [CHILLICOLLECTIVO_LICENSE.TRIAL_STARTED_KEY]: 1,
        [CHILLICOLLECTIVO_LICENSE.TRIAL_CONSUMED_KEY]: true,
      });
      return 1;
    }
    return null;
  }

  async function chillicollectivoScheduleLicenseRevalidateAlarm() {
    if (typeof chrome === 'undefined' || !chrome.alarms?.create) return;
    const periodMinutes = chillicollectivoIsStrictServerLicenseMode() ? 5 : 60;
    await chrome.alarms.create(CHILLICOLLECTIVO_LICENSE.LICENSE_REVALIDATE_ALARM, {
      periodInMinutes: periodMinutes,
    });
  }

  async function chillicollectivoBootstrapLicense(options = {}) {
    if (await chillicollectivoIsLicenseForceLocked()) {
      return chillicollectivoGetLicenseState({
        ...options,
        revalidate: false,
        startTrial: false,
      });
    }
    if (await chillicollectivoIsLicenseActivating()) {
      return chillicollectivoGetLicenseState({
        ...options,
        revalidate: false,
        startTrial: false,
      });
    }
    await chillicollectivoRecoverLicenseFromCookie();
    await chillicollectivoRecoverTrialFromCookie();
    const state = await chillicollectivoGetLicenseState(options);
    await chillicollectivoScheduleTrialExpiryWatch();
    await chillicollectivoScheduleLicenseRevalidateAlarm();
    return state;
  }

  async function chillicollectivoIsTrialConsumed() {
    const data = await chillicollectivoLicenseStorageGet([CHILLICOLLECTIVO_LICENSE.TRIAL_CONSUMED_KEY]);
    if (data[CHILLICOLLECTIVO_LICENSE.TRIAL_CONSUMED_KEY]) return true;
    const cookie = await chillicollectivoGetCookieValue(CHILLICOLLECTIVO_LICENSE.TRIAL_CONSUMED_COOKIE_NAME);
    return cookie === '1';
  }

  async function chillicollectivoMarkTrialConsumed() {
    await chillicollectivoLicenseStorageSet({
      [CHILLICOLLECTIVO_LICENSE.TRIAL_CONSUMED_KEY]: true,
    });
    const expirationDate = Math.floor(Date.now() / 1000)
      + (CHILLICOLLECTIVO_LICENSE.TRIAL_COOKIE_RETENTION_DAYS * 86400);
    await chillicollectivoSetCookieValue(
      CHILLICOLLECTIVO_LICENSE.TRIAL_CONSUMED_COOKIE_NAME,
      '1',
      expirationDate
    );
  }

  async function chillicollectivoGetTrialCookieStartedAt() {
    const raw = await chillicollectivoGetCookieValue(CHILLICOLLECTIVO_LICENSE.TRIAL_COOKIE_NAME);
    if (!raw) return null;
    const ts = Number(raw);
    return Number.isFinite(ts) && ts > 0 ? ts : null;
  }

  async function chillicollectivoSetTrialCookieStartedAt(startedAt) {
    const value = String(startedAt);
    const expirationDate = Math.floor(startedAt / 1000)
      + (CHILLICOLLECTIVO_LICENSE.TRIAL_COOKIE_RETENTION_DAYS * 86400);
    await chillicollectivoSetCookieValue(
      CHILLICOLLECTIVO_LICENSE.TRIAL_COOKIE_NAME,
      value,
      expirationDate
    );
  }

  async function chillicollectivoResolveTrialStartedAt() {
    const data = await chillicollectivoLicenseStorageGet([CHILLICOLLECTIVO_LICENSE.TRIAL_STARTED_KEY]);
    const local = Number(data[CHILLICOLLECTIVO_LICENSE.TRIAL_STARTED_KEY]);
    const cookie = await chillicollectivoGetTrialCookieStartedAt();
    let startedAt = null;
    if (Number.isFinite(local) && local > 0 && cookie) {
      startedAt = Math.min(local, cookie);
    } else if (Number.isFinite(local) && local > 0) {
      startedAt = local;
    } else if (cookie) {
      startedAt = cookie;
    }
    return startedAt;
  }

  async function chillicollectivoPersistTrialStartedAt(startedAt) {
    await chillicollectivoLicenseStorageSet({ [CHILLICOLLECTIVO_LICENSE.TRIAL_STARTED_KEY]: startedAt });
    await chillicollectivoSetTrialCookieStartedAt(startedAt);
  }

  async function chillicollectivoOnAccessExpired() {
    const state = await chillicollectivoGetLicenseState({ revalidate: false, startTrial: false });
    await chillicollectivoBroadcastLicenseState(state);
    for (const fn of chillicollectivoTrialExpiredHandlers) {
      try {
        await fn(state);
      } catch (_) {}
    }
  }

  async function chillicollectivoOnTrialExpired() {
    return chillicollectivoOnAccessExpired();
  }

  function chillicollectivoAccessExpiryWatchDelayMs(remainingMs) {
    if (remainingMs <= 0) return 0;
    if (remainingMs < 60 * 1000) return remainingMs + 100;
    if (remainingMs < 60 * 60 * 1000) return Math.min(remainingMs + 100, 10 * 1000);
    return Math.min(remainingMs, 60 * 1000);
  }

  async function chillicollectivoScheduleAccessExpiryWatch() {
    if (chillicollectivoTrialExpiryTimer) {
      clearTimeout(chillicollectivoTrialExpiryTimer);
      chillicollectivoTrialExpiryTimer = null;
    }

    const state = await chillicollectivoGetLicenseState({
      revalidate: false,
      startTrial: false,
      scheduleWatch: false,
    });
    if (state.access !== 'granted') {
      await chillicollectivoOnAccessExpired();
      return;
    }

    const remaining = chillicollectivoResolveStateRemainingMs(state);
    if (remaining <= 0) {
      await chillicollectivoOnAccessExpired();
      return;
    }

    const delay = chillicollectivoAccessExpiryWatchDelayMs(remaining);
    chillicollectivoTrialExpiryTimer = setTimeout(() => {
      chillicollectivoScheduleAccessExpiryWatch().catch(() => {});
    }, delay);
  }

  async function chillicollectivoScheduleTrialExpiryWatch() {
    return chillicollectivoScheduleAccessExpiryWatch();
  }

  async function chillicollectivoEnsureTrialStarted() {
    const existing = await chillicollectivoResolveTrialStartedAt();
    if (existing) {
      await chillicollectivoPersistTrialStartedAt(existing);
      await chillicollectivoMarkTrialConsumed();
      await chillicollectivoScheduleTrialExpiryWatch();
      return existing;
    }
    if (await chillicollectivoIsTrialConsumed()) {
      return 1;
    }
    const startedAt = Date.now();
    await chillicollectivoMarkTrialConsumed();
    await chillicollectivoPersistTrialStartedAt(startedAt);
    await chillicollectivoScheduleTrialExpiryWatch();
    return startedAt;
  }

  async function chillicollectivoGetLicenseState(options = {}) {
    const data = await chillicollectivoLicenseStorageGet([
      CHILLICOLLECTIVO_LICENSE.STORAGE_KEY,
      CHILLICOLLECTIVO_LICENSE.TRIAL_STARTED_KEY,
      CHILLICOLLECTIVO_LICENSE.FORCE_LOCK_KEY,
    ]);
    let license = data[CHILLICOLLECTIVO_LICENSE.STORAGE_KEY] || null;
    let trialStartedAt = null;
    const forceLocked = !!data[CHILLICOLLECTIVO_LICENSE.FORCE_LOCK_KEY];

    if (forceLocked && !license?.valid) {
      await chillicollectivoSyncLicenseFeaturesCache(null);
      return {
        access: 'denied',
        reason: 'no_license',
        message: 'Keine gültige Lizenz – Mic ist gesperrt.',
        license: null,
        trialRemainingMs: 0,
        licenseRemainingMs: 0,
        features: { chiliStimmung: false },
      };
    }

    if (license?.expiresAt) {
      const normalizedExpiry = chillicollectivoNormalizeExpiryMs(license.expiresAt);
      if (normalizedExpiry != null && normalizedExpiry !== Number(license.expiresAt)) {
        license = { ...license, expiresAt: normalizedExpiry };
        await chillicollectivoLicenseStorageSet({ [CHILLICOLLECTIVO_LICENSE.STORAGE_KEY]: license });
      }
    }

    if (license?.valid === true && chillicollectivoIsLicenseExpired(license)) {
      license = await chillicollectivoInvalidateStoredLicense(license, 'Lizenz abgelaufen.');
    }

    if (license?.key && license.valid !== true && !forceLocked) {
      const recovered = await chillicollectivoTryRefreshLocalLicense(license.key, { silent: true });
      if (recovered?.valid) license = recovered;
    }

    if (!license?.valid && !forceLocked && !(await chillicollectivoIsLicenseActivating())) {
      const cookieKey = await chillicollectivoGetLicenseCookieKey();
      if (cookieKey) {
        const recovered = await chillicollectivoValidateLicenseKey(cookieKey, { silent: true });
        if (recovered?.valid) license = recovered;
      }
    }

    if (license?.valid) {
      await chillicollectivoSetLicenseForceLocked(false);
      await chillicollectivoPersistActivatedLicense(license);
      if (options.scheduleWatch !== false) {
        await chillicollectivoScheduleAccessExpiryWatch();
      }
    } else {
      trialStartedAt = await chillicollectivoResolveTrialStartedAt();
      const hasLicenseCookie = !!(await chillicollectivoGetLicenseCookieKey());
      if (!trialStartedAt && !hasLicenseCookie && options.startTrial !== false && !forceLocked) {
        if (await chillicollectivoIsTrialConsumed()) {
          trialStartedAt = 1;
        } else {
          trialStartedAt = await chillicollectivoEnsureTrialStarted();
        }
      } else if (trialStartedAt) {
        await chillicollectivoPersistTrialStartedAt(trialStartedAt);
        if (options.scheduleWatch !== false) {
          await chillicollectivoScheduleAccessExpiryWatch();
        }
      }
    }

    const state = chillicollectivoBuildLicenseState(license, trialStartedAt);
    await chillicollectivoSyncLicenseFeaturesCache(license?.valid ? license : null);

    const revalidateIntervalElapsed = !license?.validatedAt
      || (Date.now() - Number(license.validatedAt)) > chillicollectivoEffectiveRevalidateMs();
    const shouldRevalidate = !forceLocked
      && options.revalidate
      && license?.key
      && license.valid
      && license.plan !== 'out_reward'
      && license.source !== 'out_milestone'
      && license.source !== 'local_offline'
      && (
        (chillicollectivoIsStrictServerLicenseMode() && license.source === 'server')
        || revalidateIntervalElapsed
      );

    if (options.revalidate && license?.valid && license?.source === 'local_offline') {
      const local = await chillicollectivoTryRefreshLocalLicense(license.key, { silent: true });
      if (local?.valid) {
        license = local;
        await chillicollectivoSyncLicenseFeaturesCache(license);
        return chillicollectivoBuildLicenseState(license, trialStartedAt);
      }
    }

    if (shouldRevalidate) {
      try {
        const refreshed = await chillicollectivoValidateLicenseKey(license.key, {
          silent: true,
          serverOnly: license.source === 'server' || chillicollectivoIsStrictServerLicenseMode(),
        });
        if (refreshed?.valid) {
          license = refreshed;
          await chillicollectivoSyncLicenseFeaturesCache(license);
          return chillicollectivoBuildLicenseState(license, trialStartedAt);
        }
        if (refreshed && refreshed.valid === false) {
          license = refreshed;
          await chillicollectivoSyncLicenseFeaturesCache(null);
          const deniedState = chillicollectivoBuildLicenseState(license, trialStartedAt);
          chillicollectivoBroadcastLicenseState(deniedState).catch(() => {});
          return deniedState;
        }
        if (!refreshed && chillicollectivoIsLicenseExpired(license)) {
          license = await chillicollectivoInvalidateStoredLicense(license, 'Lizenz abgelaufen.');
        }
      } catch (_) {}

      if (license?.valid === false) {
        return chillicollectivoBuildLicenseState(license, trialStartedAt);
      }

      if (license?.source === 'local_offline' || await chillicollectivoFindOfflineLicenseEntry(
        await chillicollectivoLoadOfflineLicenses(),
        chillicollectivoNormalizeLicenseKey(license?.key)
      )) {
        const local = await chillicollectivoTryRefreshLocalLicense(license.key, { silent: true });
        if (local?.valid) {
          license = local;
          await chillicollectivoSyncLicenseFeaturesCache(license);
          return chillicollectivoBuildLicenseState(license, trialStartedAt);
        }
      }
    }

    return state;
  }

  async function chillicollectivoIsLicensed(options = {}) {
    const state = await chillicollectivoGetLicenseState(options);
    return state.access === 'granted';
  }

  async function chillicollectivoValidateLicenseKey(key, options = {}) {
    const normalized = chillicollectivoNormalizeLicenseKey(key);
    if (!normalized || normalized.length < 10) {
      throw new Error('Bitte einen gültigen Lizenzschlüssel eingeben.');
    }
    if (options.activate === true) {
      const email = options.email ? String(options.email).trim().toLowerCase() : '';
      if (!email) {
        throw new Error('Bitte E-Mail eingeben.');
      }
    }

    if (chillicollectivoIsOutRewardLicenseKey(normalized)) {
      if (options.silent) return null;
      throw new Error('Out-Bonus-Lizenzen sind nicht mehr gültig.');
    }

    if (options.localOnly) {
      const localOnly = await chillicollectivoTryRefreshLocalLicense(normalized, { silent: options.silent });
      if (localOnly?.valid) return localOnly;
      if (options.silent) return null;
      throw new Error('Offline-Schlüssel unbekannt.');
    }

    if (!options.serverOnly && !chillicollectivoIsStrictServerLicenseMode()) {
      const localFirst = await chillicollectivoTryRefreshLocalLicense(normalized, { silent: true });
      if (localFirst?.valid) return localFirst;
    }

    const extensionId = typeof chrome !== 'undefined' && chrome.runtime?.id ? chrome.runtime.id : null;
    const deviceId = await chillicollectivoGetOrCreateDeviceId();

    const requestBody = {
      key: normalized,
      extensionId,
      deviceId,
      extensionVersion: chillicollectivoGetExtensionVersion(),
      doActivate: options.activate === true,
    };
    if (options.email) {
      requestBody.email = String(options.email).trim().toLowerCase();
    }

    const { response, payload, networkError } = await chillicollectivoPostLicenseApi(requestBody, {
      timeoutMs: options.activate ? 15000 : 10000,
      retries: options.activate ? 2 : 1,
    });

    if (networkError || !response) {
      const local = await chillicollectivoTryRefreshLocalLicense(normalized, { silent: options.silent });
      if (local?.valid) return local;
      if (options.silent) return null;
      throw new Error('Lizenzserver nicht erreichbar. Bitte Internet prüfen, Extension neu laden und erneut versuchen.');
    }

    if (payload.micUpdate) {
      await chillicollectivoStoreMicUpdateInfo(payload.micUpdate);
    }

    const now = Date.now();
    const prev = (await chillicollectivoLicenseStorageGet([CHILLICOLLECTIVO_LICENSE.STORAGE_KEY]))[CHILLICOLLECTIVO_LICENSE.STORAGE_KEY] || {};

    if (!response.ok || !payload.valid) {
      if (networkError) {
        const local = await chillicollectivoTryRefreshLocalLicense(normalized, { silent: options.silent });
        if (local?.valid) return local;
      }

      if (payload.pending && (options.silent || !options.activate)) {
        return null;
      }

      const activationAttempt = Number(options._activationAttempt || 0);
      if (payload.pending && options.activate === true && activationAttempt < 2) {
        await new Promise((resolve) => setTimeout(resolve, 400 + (activationAttempt * 350)));
        return chillicollectivoValidateLicenseKey(key, {
          ...options,
          _activationRetry: true,
          _activationAttempt: activationAttempt + 1,
        });
      }

      if (payload.error === 'version_outdated' || payload.status === 'version_outdated') {
        const versionMessage = payload.message
          || payload.micUpdate?.message
          || 'Mic-Version veraltet – bitte aktualisieren.';
        if (options.silent) return null;
        throw new Error(versionMessage);
      }

      const deniedMessage = chillicollectivoUserFacingLicenseError(
        {
          status: payload.status,
          message: payload.message
            || (payload.pending ? 'Lizenz noch nicht gestartet – bitte in den Einstellungen auf Aktivieren klicken.' : '')
            || payload.error
            || chillicollectivoHttpLicenseErrorMessage(response.status)
            || 'Lizenz ungültig oder gesperrt.',
        },
        chillicollectivoHttpLicenseErrorMessage(response.status) || 'Lizenz ungültig oder gesperrt.',
      );
      const serverRevoked = chillicollectivoIsServerExplicitDenial(payload, response);
      const explicitlyDenied = serverRevoked
        || /abgelaufen|gesperrt|expired|revoked|gebunden|device_mismatch|anderen computer|unbekannt|not_found|gelöscht|geloescht|deleted|ungültig|ungueltig/i.test(String(deniedMessage));
      const failed = {
        ...prev,
        key: normalized,
        valid: false,
        validatedAt: explicitlyDenied ? (prev.validatedAt || now) : now,
        lastError: deniedMessage,
        email: payload.email || prev.email || null,
        plan: payload.plan || prev.plan || null,
        expiresAt: chillicollectivoNormalizeExpiryMs(payload.expiresAt) || prev.expiresAt || null,
        status: payload.status || (explicitlyDenied ? 'revoked' : (prev.status || 'revoked')),
        source: prev.source || 'server',
      };
      if (options.silent) {
        if (serverRevoked || explicitlyDenied) {
          const invalidated = await chillicollectivoInvalidateStoredLicense(
            { ...failed, key: normalized },
            deniedMessage,
            String(payload.status || payload.error || 'revoked').toLowerCase(),
          );
          return invalidated;
        }
        return null;
      }
      if (!options.activate) {
        await chillicollectivoLicenseStorageSet({ [CHILLICOLLECTIVO_LICENSE.STORAGE_KEY]: failed });
        if (explicitlyDenied) {
          await chillicollectivoClearLicenseCookieKey();
        }
      }
      throw new Error(failed.lastError);
    }

    const license = {
      key: normalized,
      valid: true,
      validatedAt: now,
      lastError: null,
      email: payload.email || (options.email ? String(options.email).trim().toLowerCase() : null) || null,
      plan: payload.plan || 'standard',
      expiresAt: chillicollectivoResolveServerLicenseExpiryMs(payload, prev, normalized, now, options),
      status: payload.status || 'active',
      features: payload.features && typeof payload.features === 'object' ? payload.features : {},
      source: 'server',
    };
    await chillicollectivoLicenseStorageSet({ [CHILLICOLLECTIVO_LICENSE.STORAGE_KEY]: license });
    await chillicollectivoSyncLicenseFeaturesCache(license);
    await chillicollectivoPersistActivatedLicense(license);
    return license;
  }

  async function chillicollectivoStoreActivatedLicenseFromPortal(key, email, payload = {}) {
    const normalized = chillicollectivoNormalizeLicenseKey(key);
    const now = Date.now();
    const license = {
      key: normalized,
      valid: true,
      validatedAt: now,
      lastError: null,
      email: payload.email || email || null,
      plan: payload.plan || 'standard',
      expiresAt: chillicollectivoResolveServerLicenseExpiryMs(payload, null, normalized, now, { activate: true }),
      status: payload.status || 'active',
      features: payload.features && typeof payload.features === 'object' ? payload.features : {},
      source: payload.source || 'portal',
    };
    await chillicollectivoLicenseStorageSet({ [CHILLICOLLECTIVO_LICENSE.STORAGE_KEY]: license });
    await chillicollectivoSyncLicenseFeaturesCache(license);
    await chillicollectivoPersistActivatedLicense(license);
    await chillicollectivoSetLicenseForceLocked(false);
    return license;
  }

  async function chillicollectivoActivateLicense(key, options = {}) {
    const normalized = chillicollectivoNormalizeLicenseKey(key);
    const email = options.email ? String(options.email).trim().toLowerCase() : '';
    if (!email) {
      throw new Error('Bitte E-Mail eingeben.');
    }
    if (!normalized || normalized.length < 10) {
      throw new Error('Bitte einen gültigen Lizenzschlüssel eingeben.');
    }

    await chillicollectivoSetLicenseActivating(true);
    try {
      const data = await chillicollectivoLicenseStorageGet([CHILLICOLLECTIVO_LICENSE.STORAGE_KEY]);
      const stored = data[CHILLICOLLECTIVO_LICENSE.STORAGE_KEY];
      if (
        stored?.key
        && chillicollectivoNormalizeLicenseKey(stored.key) === normalized
        && stored.valid !== true
      ) {
        await chillicollectivoLicenseStorageRemove([CHILLICOLLECTIVO_LICENSE.STORAGE_KEY]);
      }

      let lastError = null;
      const retryDelays = [0, 500, 900];
      for (let attempt = 0; attempt < retryDelays.length; attempt++) {
        if (retryDelays[attempt] > 0) {
          await new Promise((resolve) => setTimeout(resolve, retryDelays[attempt]));
        }
        try {
          const license = await chillicollectivoValidateLicenseKey(key, {
            silent: false,
            activate: true,
            email,
            _activationRetry: attempt > 0,
            _activationAttempt: attempt,
          });
          if (license?.valid) {
            await chillicollectivoSetLicenseForceLocked(false);
            return license;
          }
          lastError = new Error(license?.lastError || 'Aktivierung fehlgeschlagen.');
        } catch (err) {
          lastError = err;
        }
      }

      throw lastError || new Error('Aktivierung fehlgeschlagen.');
    } finally {
      await chillicollectivoSetLicenseActivating(false);
    }
  }

  async function chillicollectivoClearLicense() {
    await chillicollectivoSetLicenseForceLocked(true);
    await chillicollectivoLicenseStorageRemove([
      CHILLICOLLECTIVO_LICENSE.STORAGE_KEY,
      CHILLICOLLECTIVO_LICENSE.TRIAL_STARTED_KEY,
    ]);
    await chillicollectivoClearLicenseCookieKey();
    await chillicollectivoClearTrialCookie();
    await chillicollectivoSyncLicenseFeaturesCache(null);
  }

  async function chillicollectivoOpenSalesPage() {
    const url = CHILLICOLLECTIVO_LICENSE.SALES_URL;
    if (typeof chrome !== 'undefined' && chrome.tabs?.create) {
      chrome.tabs.create({ url });
      return;
    }
    if (typeof global.open === 'function') global.open(url, '_blank', 'noopener');
  }

  async function chillicollectivoOpenLicenseOptions() {
    if (typeof chillicollectivoOpenWebMicOptions === 'function') {
      try {
        if (await chillicollectivoOpenWebMicOptions()) return;
      } catch (_) {}
    }
    if (typeof chrome !== 'undefined' && chrome.runtime?.openOptionsPage) {
      try {
        await chrome.runtime.openOptionsPage();
        return;
      } catch (_) {}
    }
    if (typeof chrome !== 'undefined' && chrome.runtime?.getURL) {
      const url = chrome.runtime.getURL('options.html#license');
      if (chrome.tabs?.create) {
        chrome.tabs.create({ url });
        return;
      }
    }
  }

  async function chillicollectivoBroadcastLicenseState(forcedState = null) {
    if (typeof chrome === 'undefined' || !chrome.tabs?.query) return;
    const state = forcedState || await chillicollectivoGetLicenseState({ revalidate: false });
    const tabs = await new Promise((resolve) => {
      chrome.tabs.query({ url: ['*://torchwood.app/*', '*://*.torchwood.app/*'] }, (result) => resolve(result || []));
    });
    for (const tab of tabs) {
      if (!tab.id) continue;
      chrome.tabs.sendMessage(tab.id, { type: 'LICENSE_STATE', state }).catch(() => {});
    }
  }

  const api = {
    CHILLICOLLECTIVO_LICENSE,
    chillicollectivoNormalizeLicenseKey,
    chillicollectivoNormalizeExpiryMs,
    chillicollectivoFormatLicenseKeyInput,
    chillicollectivoFormatTrialRemaining,
    chillicollectivoFormatTrialCountdown,
    chillicollectivoFormatLicenseCountdown,
    chillicollectivoLicensePlanLabel,
    chillicollectivoResolveLicenseCountdown,
    chillicollectivoCountdownUsesClockFormat,
    chillicollectivoBuildLicenseState,
    chillicollectivoEnsureTrialStarted,
    chillicollectivoBootstrapLicense,
    chillicollectivoRecoverLicenseFromCookie,
    chillicollectivoRecoverTrialFromCookie,
    chillicollectivoGetLicenseState,
    chillicollectivoIsLicensed,
    chillicollectivoValidateLicenseKey,
    chillicollectivoValidateLicenseKeyLocally,
    chillicollectivoLoadOfflineLicenses,
    chillicollectivoGetOrCreateDeviceId,
    chillicollectivoGetStoredLicenseKey,
    chillicollectivoGetExtensionVersion,
    chillicollectivoGetMicUpdateInfo,
    chillicollectivoStoreMicUpdateInfo,
    chillicollectivoFetchMicUpdateFromServer,
    chillicollectivoResolveMicUpdateDownloads,
    chillicollectivoOpenMicUpdateDownload,
    chillicollectivoActivateLicense,
    chillicollectivoClearLicense,
    chillicollectivoIsLicenseForceLocked,
    chillicollectivoSetLicenseForceLocked,
    chillicollectivoIsLicenseActivating,
    chillicollectivoSetLicenseActivating,
    chillicollectivoOpenSalesPage,
    chillicollectivoOpenLicenseOptions,
    chillicollectivoBroadcastLicenseState,
    chillicollectivoResolveStateRemainingMs,
    chillicollectivoScheduleAccessExpiryWatch,
    chillicollectivoScheduleTrialExpiryWatch,
    chillicollectivoOnAccessExpired,
    chillicollectivoRegisterTrialExpiredHandler,
    chillicollectivoIsOutRewardLicenseKey,
    chillicollectivoGetOutRewardRecord,
    chillicollectivoTryGrantOutMilestoneReward,
    chillicollectivoSyncOutCounterTotal,
    chillicollectivoResolveLicenseFeatures,
    chillicollectivoSyncLicenseFeaturesCache,
    chillicollectivoLicenseStateHasFeature,
    chillicollectivoHasChiliStimmungAccess,
    chillicollectivoEnsureChiliStimmungDefaults,
  };

  Object.assign(global, api);

  if (typeof chrome !== 'undefined' && chrome.alarms?.onAlarm && !global.__chillicollectivoLicenseAlarmReady) {
    global.__chillicollectivoLicenseAlarmReady = true;
    chrome.alarms.onAlarm.addListener((alarm) => {
      if (alarm.name !== CHILLICOLLECTIVO_LICENSE.LICENSE_REVALIDATE_ALARM) return;
      chillicollectivoGetLicenseState({ revalidate: true, startTrial: false })
        .then((state) => chillicollectivoBroadcastLicenseState(state))
        .catch(() => {});
    });
  }
})(typeof globalThis !== 'undefined' ? globalThis : self);
