const FIELDS = [
  'speechLang',
  'previewEnabled',
  'previewMovable',
  'previewPinned',
  'previewEnterToInsert',
  'previewClickToInsert',
  'previewClickFlushToInsert',
  'previewInsertHotkey',
  'ppAutoInsert',
  'previewOpacity',
  'previewColor',
  'previewFontWeight',
  'previewTextCase',
  'previewFontSize',
  'toolColor',
  'toolOpacity',
  'fabGearIcon',
  'micTipsEnabled',
  'replyToLastCustomer',
  'sendCrumbleIntensity',
  'sharpSAsDoubleS',
];

let settings = {};
let settingsHydrated = false;
let galleryCmdConfig = null;
let galleryCmdHydrated = false;
let recordingHotkey = false;
let recordingPreviewInsertHotkey = false;
let recordingTabEnterHotkey = false;
let toastTimer = null;
const CHILLICOLLECTIVO_OUT_COUNTER_KEY = 'chillicollectivoOutCounter';
const CHILLICOLLECTIVO_OUT_COUNTER_TOTAL_KEY = 'chillicollectivoOutCounterTotal';
const CHILLICOLLECTIVO_OUT_TARGET_KEY = 'chillicollectivoOutTarget';
const CHILLICOLLECTIVO_OUT_COUNTER_ENABLED_KEY = 'chillicollectivoOutCounterEnabled';
const CHILLICOLLECTIVO_CHILI_STIMMUNG_ENABLED_KEY = 'chillicollectivoChiliStimmungEnabled';
const CHILLICOLLECTIVO_CHILI_STIMMUNG_SETTINGS_KEY = 'chillicollectivoChiliStimmungSettings';
const CHILLICOLLECTIVO_CHILI_STIMMUNG_SETTINGS_LEGACY_KEY = 'chillicollectivoMuppetSettings';
const CHILLICOLLECTIVO_OUT_REWARD_MILESTONE = 25000;

const hotkeyDisplay = document.getElementById('hotkeyDisplay');
const hotkeyHint = document.getElementById('hotkeyHint');
const previewInsertHotkeyDisplay = document.getElementById('previewInsertHotkeyDisplay');
const previewInsertHotkeyHint = document.getElementById('previewInsertHotkeyHint');
const previewInsertHotkeyRow = document.getElementById('previewInsertHotkeyRow');
const tabEnterHotkeyDisplay = document.getElementById('tabEnterHotkeyDisplay');
const tabEnterHotkeyHint = document.getElementById('tabEnterHotkeyHint');
const toast = document.getElementById('toast');
const outCounterStatus = document.getElementById('outCounterStatus');
const outTotalHint = document.getElementById('outTotalHint');
const outRewardHint = document.getElementById('outRewardHint');
const outTargetInput = document.getElementById('outTargetInput');
const outTargetHint = document.getElementById('outTargetHint');
const outCounterEnabledInput = document.getElementById('outCounterEnabled');
const voiceMessageLogStatus = document.getElementById('voiceMessageLogStatus');
const voiceMessageLogClearStatus = document.getElementById('voiceMessageLogClearStatus');
const voiceMessageLogPreview = document.getElementById('voiceMessageLogPreview');
const VOICE_MESSAGE_LOG_STORAGE_KEY = 'chillicollectivoVoiceMessageLog';
const previewOpacityInput = document.getElementById('previewOpacity');
const previewOpacityValue = document.getElementById('previewOpacityValue');
const previewColorInput = document.getElementById('previewColor');
const previewColorSwatch = document.getElementById('previewColorSwatch');
const previewFontWeightInput = document.getElementById('previewFontWeight');
const previewTextCaseInput = document.getElementById('previewTextCase');
const previewFontSizeInput = document.getElementById('previewFontSize');
const previewFontSizeValue = document.getElementById('previewFontSizeValue');
const toolColorInput = document.getElementById('toolColor');
const toolColorSwatch = document.getElementById('toolColorSwatch');
const toolOpacityInput = document.getElementById('toolOpacity');
const toolOpacityValue = document.getElementById('toolOpacityValue');
const sendCrumbleIntensityInput = document.getElementById('sendCrumbleIntensity');
const sendCrumbleIntensityValue = document.getElementById('sendCrumbleIntensityValue');

const INTENSITY_FIELDS = [
  ['sendCrumbleIntensity', sendCrumbleIntensityInput, sendCrumbleIntensityValue],
  ['previewOpacity', previewOpacityInput, previewOpacityValue, 0],
  ['toolOpacity', toolOpacityInput, toolOpacityValue, 20],
];

function formatHotkeyKeyLabel(key, code) {
  if (typeof chillicollectivoFormatHotkeyKeyLabel === 'function') {
    return chillicollectivoFormatHotkeyKeyLabel(key, code);
  }
  const labels = {
    ArrowLeft: 'Linkstaste',
    ArrowRight: 'Rechtstaste',
    ArrowUp: 'Oben',
    ArrowDown: 'Unten',
    Enter: 'Enter',
    Tab: 'Tab',
    ' ': 'Leertaste',
  };
  if (labels[key]) return labels[key];
  if (String(key || '').length === 1) return String(key).toUpperCase();
  return String(key || '');
}

function formatHotkey(hk) {
  if (!hk?.key && !hk?.code) return null;
  const isMac = navigator.platform.toUpperCase().includes('MAC');
  const keyLabel = formatHotkeyKeyLabel(hk.key, hk.code);
  if (isMac) {
    let out = '';
    if (hk.ctrlKey) out += '⌃';
    if (hk.altKey) out += '⌥';
    if (hk.shiftKey) out += '⇧';
    if (hk.metaKey) out += '⌘';
    out += keyLabel;
    return out;
  }
  const parts = [];
  if (hk.ctrlKey) parts.push('Ctrl');
  if (hk.shiftKey) parts.push('Shift');
  if (hk.altKey) parts.push('Alt');
  if (hk.metaKey) parts.push(navigator.platform.toUpperCase().includes('MAC') ? 'Cmd' : 'Meta');
  parts.push(keyLabel);
  return parts.length === 1 ? keyLabel : parts.join('+');
}

function formatDefaultHotkeyLabel() {
  const isMac = navigator.platform.toUpperCase().includes('MAC');
  return isMac ? '⌥J' : 'Alt+J';
}

function formatDefaultPreviewInsertHotkeyLabel() {
  return formatHotkey({ key: 'Enter', ctrlKey: false, shiftKey: false, altKey: false, metaKey: false }) || 'Enter';
}

function updateHotkeyDisplay() {
  if (!hotkeyDisplay) return;
  hotkeyDisplay.textContent = formatHotkey(settings.hotkey) || `Standard (${formatDefaultHotkeyLabel()})`;
}

function updatePreviewInsertHotkeyDisplay() {
  if (!previewInsertHotkeyDisplay) return;
  previewInsertHotkeyDisplay.textContent = formatHotkey(settings.previewInsertHotkey)
    || `Standard (${formatDefaultPreviewInsertHotkeyLabel()})`;
}

function updateTabEnterHotkeyDisplay() {
  if (!tabEnterHotkeyDisplay) return;
  tabEnterHotkeyDisplay.textContent = formatHotkey(settings.tabEnterHotkey) || 'Nicht festgelegt';
}

function normalizeEffectIntensity(value, min = 0) {
  const n = Number(value);
  if (!Number.isFinite(n)) return min === 20 ? 100 : 100;
  return Math.min(100, Math.max(min, Math.round(n / 5) * 5));
}

function normalizePreviewOpacity(value) {
  return normalizeEffectIntensity(value, 0);
}

function normalizePreviewFontWeight(value) {
  const raw = String(value || '').trim().toLowerCase();
  if (raw === 'light' || raw === '300') return 'light';
  if (raw === 'semibold' || raw === 'semi' || raw === '600') return 'semibold';
  if (raw === 'extrabold' || raw === 'extra' || raw === '800' || raw === 'bold') return 'extrabold';
  return 'light';
}

function normalizePreviewTextCase(value) {
  const raw = String(value || '').trim().toLowerCase();
  if (raw === 'sentence' || raw === 'normal' || raw === 'auto') return 'sentence';
  if (raw === 'spoken' || raw === 'raw' || raw === 'original') return 'spoken';
  if (raw === 'lowercase' || raw === 'lower' || raw === 'klein') return 'lowercase';
  if (raw === 'uppercase' || raw === 'upper' || raw === 'gross' || raw === 'groß') return 'uppercase';
  return 'sentence';
}

function normalizePreviewFontSize(value) {
  const n = Number(value);
  if (!Number.isFinite(n)) return 22;
  return Math.min(32, Math.max(16, Math.round(n)));
}

function updatePreviewFontSizeLabel() {
  if (!previewFontSizeValue || !previewFontSizeInput) return;
  previewFontSizeValue.textContent = `${normalizePreviewFontSize(previewFontSizeInput.value)} px`;
}

function normalizeToolOpacity(value) {
  return normalizeEffectIntensity(value, 20);
}

function legacyIntensity(value, legacyEnabled, fallback = 100) {
  if (value != null && Number.isFinite(Number(value))) {
    return normalizeEffectIntensity(value, 0);
  }
  if (legacyEnabled === false) return 0;
  if (legacyEnabled === true) return fallback;
  return fallback;
}

function updateIntensityLabel(inputEl, labelEl, min = 0) {
  if (!labelEl) return;
  const value = normalizeEffectIntensity(inputEl?.value, min);
  labelEl.textContent = value <= 0 ? 'Aus' : `${value}%`;
}

function normalizeHexColor(value) {
  const raw = String(value || '').trim();
  if (/^#[0-9a-f]{6}$/i.test(raw)) return raw.toUpperCase();
  if (/^#[0-9a-f]{3}$/i.test(raw)) {
    const r = raw[1];
    const g = raw[2];
    const b = raw[3];
    return `#${r}${r}${g}${g}${b}${b}`.toUpperCase();
  }
  return '#D46E6E';
}

function normalizePreviewColor(value) {
  return normalizeHexColor(value);
}

function hexToRgbParts(hex) {
  const norm = normalizeHexColor(hex).slice(1);
  return {
    r: parseInt(norm.slice(0, 2), 16),
    g: parseInt(norm.slice(2, 4), 16),
    b: parseInt(norm.slice(4, 6), 16),
  };
}

function mixHexWithWhite(hex, whiteAmount = 0.45) {
  const { r, g, b } = hexToRgbParts(hex);
  const mix = (channel) => Math.round(channel + (255 - channel) * whiteAmount);
  const toHex = (channel) => mix(channel).toString(16).padStart(2, '0');
  return `#${toHex(r)}${toHex(g)}${toHex(b)}`.toUpperCase();
}

function applyToolColorToOptionsPage(hex) {
  const color = normalizeHexColor(hex);
  const { r, g, b } = hexToRgbParts(color);
  const light = hexToRgbParts(mixHexWithWhite(color, 0.45));
  document.body.style.setProperty('--chillicollectivo-tool-accent', color);
  document.body.style.setProperty('--chillicollectivo-tool-accent-rgb', `${r}, ${g}, ${b}`);
  document.body.style.setProperty('--chillicollectivo-tool-accent-light-rgb', `${light.r}, ${light.g}, ${light.b}`);
}

function updateColorField(value, { input, swatch } = {}) {
  const hex = normalizeHexColor(value);
  if (swatch) swatch.style.background = hex;
  if (input && input.value.toUpperCase() !== hex) input.value = hex;
  return hex;
}

function updatePreviewColorLabel(value) {
  updateColorField(value, {
    input: previewColorInput,
    swatch: previewColorSwatch,
  });
}

function updateToolColorLabel(value) {
  const hex = updateColorField(value, {
    input: toolColorInput,
    swatch: toolColorSwatch,
  });
  applyToolColorToOptionsPage(hex);
}

function readForm() {
  return {
    speechLang: 'de-CH',
    previewEnabled: document.getElementById('previewEnabled')?.checked !== false,
    previewMovable: document.getElementById('previewEnabled')?.checked !== false
      && document.getElementById('previewMovable')?.checked === true,
    previewPinned: false,
    previewEnterToInsert: false,
    previewClickToInsert: document.getElementById('previewClickToInsert')?.checked === true,
    previewClickFlushToInsert: document.getElementById('previewClickFlushToInsert')?.checked === true,
    ppAutoInsert: false,
    previewInsertHotkey: settings.previewInsertHotkey ?? null,
    tabEnterHotkey: null,
    previewOpacity: normalizePreviewOpacity(document.getElementById('previewOpacity')?.value),
    previewColor: normalizeHexColor(document.getElementById('previewColor')?.value),
    previewFontWeight: normalizePreviewFontWeight(document.getElementById('previewFontWeight')?.value),
    previewTextCase: 'sentence',
    previewFontSize: normalizePreviewFontSize(document.getElementById('previewFontSize')?.value),
    toolColor: normalizeHexColor(document.getElementById('toolColor')?.value),
    toolOpacity: normalizeToolOpacity(document.getElementById('toolOpacity')?.value),
    fabGearIcon: document.getElementById('fabGearIcon')?.value === 'mic' ? 'mic' : 'leaf',
    micTipsEnabled: document.getElementById('micTipsEnabled')?.checked === true,
    replyToLastCustomer: document.getElementById('replyToLastCustomer')?.checked !== false,
    sendCrumbleIntensity: normalizeEffectIntensity(document.getElementById('sendCrumbleIntensity')?.value, 0),
    sharpSAsDoubleS: true,
    hotkey: settings.hotkey ?? null,
    voiceSmileysRaw: window.ChillicollectivoVoiceSmileysOptions?.readRaw?.()
      || document.getElementById('voiceSmileysRaw')?.value
      || '',
    autoCorrectionsRaw: window.ChillicollectivoVoiceCorrectionsOptions?.readRaw?.()
      || document.getElementById('autoCorrectionsRaw')?.value
      || '',
  };
}

function syncNachrichtSendenControls() {
  const previewOn = document.getElementById('previewClickToInsert')?.checked === true;
  const clickFlushOn = document.getElementById('previewClickFlushToInsert')?.checked === true;
  const hotkeyRow = document.getElementById('previewInsertHotkeyRow');
  const clickFlushRow = document.getElementById('previewClickFlushRow');
  if (hotkeyRow) hotkeyRow.classList.toggle('hidden', !previewOn);
  if (clickFlushRow) clickFlushRow.classList.toggle('hidden', !previewOn);
  const hintEl = document.getElementById('nachrichtSendenHint');
  if (hintEl) {
    if (!previewOn) {
      hintEl.textContent = 'Standard: Text landet automatisch im Chatfeld, während du sprichst. Optional oben aktivieren, wenn du erst in der Vorschau sammeln und per Taste einfügen willst.';
    } else if (clickFlushOn) {
      hintEl.textContent = 'Text landet in der Live-Vorschau. Mit Runterholen-Taste oder Klick ins gewünschte Textfeld fügst du ihn ein.';
    } else {
      hintEl.textContent = 'Text landet in der Live-Vorschau. Mit der Runterholen-Taste fügst du ihn ins gewünschte Textfeld ein.';
    }
  }
}

function syncPreviewDependentControls() {
  const previewEnabledEl = document.getElementById('previewEnabled');
  const previewOn = previewEnabledEl?.checked !== false;
  const previewMovableEl = document.getElementById('previewMovable');
  const previewMovableRow = document.getElementById('previewMovableRow');
  const previewOpacityRow = document.getElementById('previewOpacityRow');

  if (previewMovableEl) {
    previewMovableEl.disabled = !previewOn;
    if (!previewOn) previewMovableEl.checked = false;
  }
  previewMovableRow?.classList.toggle('is-disabled', !previewOn);
  if (previewOpacityInput) {
    previewOpacityInput.disabled = !previewOn;
  }
  previewOpacityRow?.classList.toggle('is-disabled', !previewOn);
}

function fillForm(data) {
  settings = { ...data, speechLang: 'de-CH', sharpSAsDoubleS: true };
  const sharpEl = document.getElementById('sharpSAsDoubleS');
  if (sharpEl) sharpEl.value = '1';
  const sendCrumbleIntensity = legacyIntensity(settings.sendCrumbleIntensity, settings.sendCrumbleEnabled);
  const previewEnabledEl = document.getElementById('previewEnabled');
  if (previewEnabledEl && previewEnabledEl.type === 'checkbox') {
    previewEnabledEl.checked = settings.previewEnabled !== false;
  }
  const previewMovableEl = document.getElementById('previewMovable');
  if (previewMovableEl) {
    previewMovableEl.checked = settings.previewEnabled !== false && settings.previewMovable === true;
  }
  if (previewTextCaseInput) {
    previewTextCaseInput.value = 'sentence';
  }
  const previewOpacity = normalizePreviewOpacity(settings.previewOpacity);
  if (previewOpacityInput) previewOpacityInput.value = String(previewOpacity);
  updateIntensityLabel(previewOpacityInput, previewOpacityValue, 0);
  updatePreviewColorLabel(settings.previewColor || '#D46E6E');
  if (previewFontWeightInput) {
    previewFontWeightInput.value = normalizePreviewFontWeight(settings.previewFontWeight);
  }
  const previewFontSize = normalizePreviewFontSize(settings.previewFontSize);
  if (previewFontSizeInput) previewFontSizeInput.value = String(previewFontSize);
  updatePreviewFontSizeLabel();
  updateToolColorLabel(settings.toolColor || settings.previewColor || '#D46E6E');
  const toolOpacity = normalizeToolOpacity(settings.toolOpacity);
  if (toolOpacityInput) toolOpacityInput.value = String(toolOpacity);
  updateIntensityLabel(toolOpacityInput, toolOpacityValue, 20);
  const fabGearIconEl = document.getElementById('fabGearIcon');
  if (fabGearIconEl) fabGearIconEl.value = settings.fabGearIcon === 'mic' ? 'mic' : 'leaf';
  const micTipsEnabledEl = document.getElementById('micTipsEnabled');
  if (micTipsEnabledEl) micTipsEnabledEl.checked = settings.micTipsEnabled === true;
  const previewClickEl = document.getElementById('previewClickToInsert');
  if (previewClickEl) previewClickEl.checked = settings.previewClickToInsert === true;
  const previewClickFlushEl = document.getElementById('previewClickFlushToInsert');
  if (previewClickFlushEl) previewClickFlushEl.checked = settings.previewClickFlushToInsert === true;
  if (sendCrumbleIntensityInput) sendCrumbleIntensityInput.value = String(sendCrumbleIntensity);
  updateIntensityLabel(sendCrumbleIntensityInput, sendCrumbleIntensityValue, 0);
  if (window.ChillicollectivoVoiceSmileysOptions?.fillTable) {
    window.ChillicollectivoVoiceSmileysOptions.fillTable(settings.voiceSmileysRaw || '');
  } else {
    const voiceSmileys = document.getElementById('voiceSmileysRaw');
    if (voiceSmileys) voiceSmileys.value = settings.voiceSmileysRaw || '';
  }
  if (window.ChillicollectivoVoiceCorrectionsOptions?.fillTable) {
    window.ChillicollectivoVoiceCorrectionsOptions.fillTable(settings.autoCorrectionsRaw || '');
  } else {
    const autoCorr = document.getElementById('autoCorrectionsRaw');
    if (autoCorr) autoCorr.value = settings.autoCorrectionsRaw || '';
  }
  syncPreviewDependentControls();
  syncNachrichtSendenControls();
  updateHotkeyDisplay();
  updatePreviewInsertHotkeyDisplay();
}

function showToast(message) {
  if (!toast) return;
  if (message) toast.textContent = message;
  toast.classList.remove('hidden');
  clearTimeout(toastTimer);
  toastTimer = setTimeout(() => {
    toast.classList.add('hidden');
    toast.textContent = 'Gespeichert';
  }, 1800);
}

function normalizeOutTarget(value) {
  if (typeof value === 'string') {
    const match = value.match(/\d+/);
    if (!match) return 0;
    value = parseInt(match[0], 10);
  }
  const n = Math.floor(Number(value));
  if (!Number.isFinite(n) || n < 0) return 0;
  return Math.min(9999, n);
}

function formatOutTargetInputValue(value) {
  const n = normalizeOutTarget(value);
  return n > 0 ? String(n) : '';
}

function updateOutTargetHint(target, enabled = true) {
  if (!outTargetHint) return;
  if (enabled === false) {
    outTargetHint.textContent = 'Out-Zähler ist aus – keine Zähl-Vorschau nach dem Senden.';
    return;
  }
  const n = normalizeOutTarget(target);
  outTargetHint.textContent = n > 0
    ? `Ziel: ${n} Outs – Vorschau zeigt z. B. 3/${n} nach dem Senden.`
    : 'Zähler an, kein Ziel – Vorschau zeigt z. B. 1 Out, 2 Outs …';
}

function syncOutCounterEnabledUi(enabled) {
  const on = enabled !== false;
  if (outCounterEnabledInput) outCounterEnabledInput.checked = on;
  if (outTargetInput) outTargetInput.disabled = !on;
  if (outCounterStatus) outCounterStatus.style.opacity = on ? '1' : '0.45';
}

function formatOutTotalLabel(total, reward) {
  const t = Math.max(0, Number(total) || 0);
  const formatted = t.toLocaleString('de-CH');
  const milestone = CHILLICOLLECTIVO_OUT_REWARD_MILESTONE.toLocaleString('de-CH');
  const claims = Number(reward?.claimsCount) || 0;
  const roundLabel = claims >= 2
    ? ' · alle Boni erhalten'
    : claims === 1
      ? ' · Bonus 1/2 erhalten'
      : '';
  return `Zähler bis nächster Bonus: ${formatted} / ${milestone} Outs${roundLabel}`;
}

function renderOutTotalHint(total, reward) {
  if (!outTotalHint) return;
  outTotalHint.textContent = formatOutTotalLabel(total, reward);
  if (!outRewardHint) return;
  const claims = Number(reward?.claimsCount) || 0;
  if (claims >= 2) {
    outRewardHint.textContent = 'Alle Out-Boni erhalten (1 Monat + 2 Monate). Keine weiteren Boni möglich.';
    outRewardHint.classList.remove('hidden');
    return;
  }
  if (claims === 1) {
    outRewardHint.textContent = 'Nächster Bonus: nochmals 25\'000 Outs → 2 Monate gratis. Danach Zähler-Reset.';
    outRewardHint.classList.remove('hidden');
    return;
  }
  outRewardHint.textContent = 'Bonus 1: 25\'000 Outs → 1 Monat gratis. Danach Zähler-Reset. Bonus 2: nochmals 25\'000 → 2 Monate.';
  outRewardHint.classList.remove('hidden');
}

function renderOutRewardBanner(reward) {
  const banner = document.getElementById('outRewardBanner');
  const keyEl = document.getElementById('outRewardKeyDisplay');
  const bannerText = document.getElementById('outRewardBannerText');
  if (!banner || !keyEl) return;
  if (!reward?.key) {
    banner.classList.add('hidden');
    keyEl.textContent = '';
    return;
  }
  const months = Number(reward.monthsGranted ?? (reward.tier === 2 ? 2 : 1));
  if (bannerText) {
    bannerText.textContent = reward.tier === 2
      ? 'Bonus 2: 25\'000 Outs – 2 Monate gratis. Dein Schlüssel:'
      : 'Bonus 1: 25\'000 Outs – 1 Monat gratis. Dein Schlüssel:';
  }
  keyEl.textContent = reward.key;
  banner.classList.remove('hidden');
}

function renderOutCounterStatus(count, target) {
  if (!outCounterStatus) return;
  const c = Math.max(0, Number(count) || 0);
  const t = normalizeOutTarget(target);
  if (t > 0) {
    outCounterStatus.textContent = `Outs: ${c}/${t}`;
    return;
  }
  outCounterStatus.textContent = c === 1 ? 'Outs: 1' : `Outs: ${c}`;
}

function showBackupStatus(message, isError = false) {
  const statusEl = document.getElementById('unifiedBackupStatus');
  if (!statusEl) return;
  if (!message) {
    statusEl.textContent = '';
    statusEl.classList.add('hidden');
    return;
  }
  statusEl.textContent = message;
  statusEl.classList.toggle('diag-log-export-warn', !!isError);
  statusEl.classList.remove('hidden');
}

async function exportDiagnosticLog() {
  const result = await window.ChillicollectivoDiagnosticLog?.exportTextFile?.();
  if (result?.ok) {
    showToast('Log exportiert');
  } else {
    showToast('Log-Export fehlgeschlagen');
  }
}

async function clearDiagnosticLog() {
  await window.ChillicollectivoDiagnosticLog?.clear?.();
  showToast('Log geleert');
}

async function loadOutCounterStatus() {
  await chillicollectivoSyncOutCounterTotal?.().catch(() => {});
  const data = await chrome.storage.local.get([
    CHILLICOLLECTIVO_OUT_COUNTER_KEY,
    CHILLICOLLECTIVO_OUT_COUNTER_TOTAL_KEY,
    CHILLICOLLECTIVO_OUT_TARGET_KEY,
    CHILLICOLLECTIVO_OUT_COUNTER_ENABLED_KEY,
  ]);
  const target = normalizeOutTarget(data?.[CHILLICOLLECTIVO_OUT_TARGET_KEY]);
  const enabled = data?.[CHILLICOLLECTIVO_OUT_COUNTER_ENABLED_KEY] !== false;
  const reward = await chillicollectivoGetOutRewardRecord?.().catch(() => null);
  if (outTargetInput) outTargetInput.value = formatOutTargetInputValue(target);
  syncOutCounterEnabledUi(enabled);
  updateOutTargetHint(target, enabled);
  renderOutCounterStatus(data?.[CHILLICOLLECTIVO_OUT_COUNTER_KEY], target);
  renderOutTotalHint(data?.[CHILLICOLLECTIVO_OUT_COUNTER_TOTAL_KEY], reward);
  renderOutRewardBanner(reward);
}

async function saveOutTarget(rawValue) {
  const target = normalizeOutTarget(rawValue);
  await chrome.storage.local.set({ [CHILLICOLLECTIVO_OUT_TARGET_KEY]: target });
  if (outTargetInput) outTargetInput.value = formatOutTargetInputValue(target);
  const enabledData = await chrome.storage.local.get(CHILLICOLLECTIVO_OUT_COUNTER_ENABLED_KEY);
  const enabled = enabledData?.[CHILLICOLLECTIVO_OUT_COUNTER_ENABLED_KEY] !== false;
  updateOutTargetHint(target, enabled);
  const data = await chrome.storage.local.get(CHILLICOLLECTIVO_OUT_COUNTER_KEY);
  renderOutCounterStatus(data?.[CHILLICOLLECTIVO_OUT_COUNTER_KEY], target);
  showToast(target > 0 ? `Out-Ziel: ${target}` : 'Out-Ziel entfernt');
}

async function saveOutCounterEnabled(enabled) {
  const on = enabled !== false;
  await chrome.storage.local.set({ [CHILLICOLLECTIVO_OUT_COUNTER_ENABLED_KEY]: on });
  syncOutCounterEnabledUi(on);
  const data = await chrome.storage.local.get([
    CHILLICOLLECTIVO_OUT_TARGET_KEY,
    CHILLICOLLECTIVO_OUT_COUNTER_KEY,
  ]);
  updateOutTargetHint(data?.[CHILLICOLLECTIVO_OUT_TARGET_KEY], on);
  renderOutCounterStatus(data?.[CHILLICOLLECTIVO_OUT_COUNTER_KEY], data?.[CHILLICOLLECTIVO_OUT_TARGET_KEY]);
  showToast(on ? 'Out-Zähler eingeschaltet' : 'Out-Zähler ausgeschaltet');
}

async function resetOutCounter() {
  await chrome.storage.local.set({ [CHILLICOLLECTIVO_OUT_COUNTER_KEY]: 0 });
  const data = await chrome.storage.local.get([
    CHILLICOLLECTIVO_OUT_TARGET_KEY,
    CHILLICOLLECTIVO_OUT_COUNTER_TOTAL_KEY,
  ]);
  const reward = await chillicollectivoGetOutRewardRecord?.().catch(() => null);
  renderOutCounterStatus(0, data?.[CHILLICOLLECTIVO_OUT_TARGET_KEY]);
  renderOutTotalHint(data?.[CHILLICOLLECTIVO_OUT_COUNTER_TOTAL_KEY], reward);
  showToast('Out-Zähler zurückgesetzt (Gesamt-Zähler bleibt)');
}

function setVoiceMessageLogStatusText(text) {
  const msg = text || 'Log bereit';
  if (voiceMessageLogStatus) voiceMessageLogStatus.textContent = msg;
  if (voiceMessageLogClearStatus) voiceMessageLogClearStatus.textContent = msg;
}

function formatVoiceLogTimestamp(iso) {
  try {
    const d = new Date(iso);
    if (Number.isNaN(d.getTime())) return String(iso || '');
    return d.toLocaleString('de-CH', {
      day: '2-digit',
      month: '2-digit',
      hour: '2-digit',
      minute: '2-digit',
      second: '2-digit',
    });
  } catch (_) {
    return String(iso || '');
  }
}

async function renderVoiceMessageLogPreview() {
  if (!voiceMessageLogPreview) return;
  const entries = await window.ChillicollectivoVoiceMessageLog?.getRecent?.(35) || [];
  if (!entries.length) {
    voiceMessageLogPreview.textContent = 'Noch keine Diktat-Einträge.';
    return;
  }
  voiceMessageLogPreview.innerHTML = entries.slice().reverse().map((entry) => {
    const kind = window.ChillicollectivoVoiceMessageLog?.kindLabel?.(entry.kind) || entry.kind;
    const route = entry.route ? ` · ${entry.route}` : '';
    const text = escapeHtml(String(entry.text || ''));
    return `<div class="voice-message-log-entry"><div class="voice-message-log-entry-meta">${escapeHtml(formatVoiceLogTimestamp(entry.ts))} · ${escapeHtml(kind)}${escapeHtml(route)}</div><div class="voice-message-log-entry-text">${text}</div></div>`;
  }).join('');
}

async function refreshVoiceMessageLogStatus() {
  const count = await window.ChillicollectivoVoiceMessageLog?.getCount?.() || 0;
  setVoiceMessageLogStatusText(count ? `Log: ${count} Einträge` : 'Log bereit');
  await renderVoiceMessageLogPreview();
}

async function exportVoiceMessageLog() {
  const result = await window.ChillicollectivoVoiceMessageLog?.exportTextFile?.();
  if (result?.ok) {
    showToast(`Diktat-Log exportiert (${result.entries})`);
    if (voiceMessageLogStatus) {
      voiceMessageLogStatus.textContent = `${result.entries} exportiert`;
    }
    window.setTimeout(() => refreshVoiceMessageLogStatus(), 2800);
    return;
  }
  showToast('Diktat-Log Export fehlgeschlagen');
}

async function clearVoiceMessageLog() {
  await window.ChillicollectivoVoiceMessageLog?.clear?.();
  await refreshVoiceMessageLogStatus();
  showToast('Diktat-Log geleert');
}

async function loadSettings(attempt = 0) {
  try {
    const response = await chrome.runtime.sendMessage({ type: 'GET_VOICE_SETTINGS' });
    if (response?.success && response.settings) {
      fillForm(response.settings);
      settingsHydrated = true;
      return;
    }
  } catch (_) {}

  if (attempt < 6) {
    await new Promise(resolve => setTimeout(resolve, 150 * (attempt + 1)));
    return loadSettings(attempt + 1);
  }

  fillForm({});
  settingsHydrated = true;
}

async function saveSettings(partial = null) {
  const payload = partial ? { ...settings, ...partial } : readForm();
  settings = payload;
  const response = await chrome.runtime.sendMessage({
    type: 'SAVE_VOICE_SETTINGS',
    settings: payload,
  });
  if (response?.success) {
    settings = response.settings || payload;
    if (partial?.hotkey !== undefined) {
      showToast('Tastenkürzel gespeichert');
    } else {
      showToast();
    }
    return true;
  }
  return false;
}

document.getElementById('previewEnabled')?.addEventListener('change', () => {
  syncPreviewDependentControls();
}, { capture: true });

document.getElementById('previewMovable')?.addEventListener('change', () => {
  syncPreviewDependentControls();
}, { capture: true });

document.getElementById('previewPinned')?.addEventListener('change', () => {
  syncPreviewDependentControls();
}, { capture: true });

document.getElementById('previewEnterToInsert')?.addEventListener('change', () => {
  syncPreviewDependentControls();
}, { capture: true });

document.getElementById('previewClickToInsert')?.addEventListener('change', () => {
  syncNachrichtSendenControls();
  if (!settingsHydrated) return;
  saveSettings();
}, { capture: true });

document.getElementById('previewClickFlushToInsert')?.addEventListener('change', () => {
  syncNachrichtSendenControls();
  if (!settingsHydrated) return;
  saveSettings();
}, { capture: true });

document.getElementById('ppAutoInsert')?.addEventListener('change', () => {
  if (!settingsHydrated) return;
  saveSettings();
}, { capture: true });

FIELDS.forEach(id => {
  const el = document.getElementById(id);
  if (!el) return;
  const eventName = el.tagName === 'TEXTAREA' ? 'blur' : 'change';
  el.addEventListener(eventName, () => {
    if (!settingsHydrated) return;
    INTENSITY_FIELDS.forEach(([fieldId, inputEl, labelEl, min = 0]) => {
      if (fieldId === id) updateIntensityLabel(inputEl, labelEl, min);
    });
    saveSettings();
  });
});

INTENSITY_FIELDS.forEach(([, inputEl, labelEl, min = 0]) => {
  if (!inputEl) return;
  inputEl.addEventListener('input', () => updateIntensityLabel(inputEl, labelEl, min));
});

if (previewFontSizeInput) {
  previewFontSizeInput.addEventListener('input', updatePreviewFontSizeLabel);
}

if (previewColorInput) {
  previewColorInput.addEventListener('input', () => updatePreviewColorLabel(previewColorInput.value));
}

if (toolColorInput) {
  toolColorInput.addEventListener('input', () => updateToolColorLabel(toolColorInput.value));
}

document.getElementById('hotkeyRecord').addEventListener('click', () => {
  recordingHotkey = true;
  hotkeyHint.classList.remove('hidden');
});

document.getElementById('hotkeyReset').addEventListener('click', async () => {
  settings.hotkey = null;
  updateHotkeyDisplay();
  await saveSettings({ hotkey: null });
});

function hotkeyFromKeyboardEvent(e) {
  if (typeof chillicollectivoHotkeyFromKeyboardEvent === 'function') {
    return chillicollectivoHotkeyFromKeyboardEvent(e);
  }
  if (['Control', 'Shift', 'Alt', 'Meta'].includes(e.key)) return null;
  if (e.key === 'Dead' || !e.key) return null;
  let key = e.key;
  if (key.length === 1 && key !== ' ') key = key.toUpperCase();
  return {
    key,
    ctrlKey: e.ctrlKey,
    shiftKey: e.shiftKey,
    altKey: e.altKey,
    metaKey: e.metaKey,
  };
}

document.getElementById('previewInsertHotkeyRecord')?.addEventListener('click', () => {
  recordingPreviewInsertHotkey = true;
  previewInsertHotkeyHint?.classList.remove('hidden');
});

document.getElementById('previewInsertHotkeyReset')?.addEventListener('click', async () => {
  settings.previewInsertHotkey = null;
  updatePreviewInsertHotkeyDisplay();
  await saveSettings({ previewInsertHotkey: null });
});

document.getElementById('tabEnterHotkeyRecord')?.addEventListener('click', () => {
  recordingTabEnterHotkey = true;
  tabEnterHotkeyHint?.classList.remove('hidden');
});

document.getElementById('tabEnterHotkeyReset')?.addEventListener('click', async () => {
  settings.tabEnterHotkey = null;
  updateTabEnterHotkeyDisplay();
  await saveSettings({ tabEnterHotkey: null });
});

window.addEventListener('keydown', e => {
  if (!recordingHotkey && !recordingPreviewInsertHotkey && !recordingTabEnterHotkey) return;
  e.preventDefault();
  if (e.key === 'Escape') {
    recordingHotkey = false;
    recordingPreviewInsertHotkey = false;
    recordingTabEnterHotkey = false;
    hotkeyHint?.classList.add('hidden');
    previewInsertHotkeyHint?.classList.add('hidden');
    tabEnterHotkeyHint?.classList.add('hidden');
    if (hotkeyHint) hotkeyHint.textContent = 'Taste oder Kombination drücken … (Esc zum Abbrechen)';
    if (previewInsertHotkeyHint) previewInsertHotkeyHint.textContent = 'Taste oder Kombination drücken … (Esc zum Abbrechen)';
    if (tabEnterHotkeyHint) tabEnterHotkeyHint.textContent = 'Taste oder Kombination drücken … (Esc zum Abbrechen)';
    return;
  }
  const hotkey = hotkeyFromKeyboardEvent(e);
  if (!hotkey) return;
  if (recordingHotkey) {
    settings.hotkey = hotkey;
    recordingHotkey = false;
    hotkeyHint?.classList.add('hidden');
    if (hotkeyHint) hotkeyHint.textContent = 'Taste oder Kombination drücken … (Esc zum Abbrechen)';
    updateHotkeyDisplay();
    saveSettings({ hotkey });
    return;
  }
  if (recordingPreviewInsertHotkey) {
    settings.previewInsertHotkey = hotkey;
    recordingPreviewInsertHotkey = false;
    previewInsertHotkeyHint?.classList.add('hidden');
    if (previewInsertHotkeyHint) previewInsertHotkeyHint.textContent = 'Taste oder Kombination drücken … (Esc zum Abbrechen)';
    updatePreviewInsertHotkeyDisplay();
    saveSettings({ previewInsertHotkey: hotkey });
    return;
  }
  if (recordingTabEnterHotkey) {
    settings.tabEnterHotkey = hotkey;
    recordingTabEnterHotkey = false;
    tabEnterHotkeyHint?.classList.add('hidden');
    if (tabEnterHotkeyHint) tabEnterHotkeyHint.textContent = 'Taste oder Kombination drücken … (Esc zum Abbrechen)';
    updateTabEnterHotkeyDisplay();
    saveSettings({ tabEnterHotkey: hotkey });
  }
});

function escapeHtml(value) {
  return String(value || '')
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;');
}

function escapeHtmlAttr(value) {
  return escapeHtml(value).replace(/"/g, '&quot;');
}

document.getElementById('resetOutCounter')?.addEventListener('click', () => resetOutCounter());
outCounterEnabledInput?.addEventListener('change', () => saveOutCounterEnabled(outCounterEnabledInput.checked));
outTargetInput?.addEventListener('change', () => saveOutTarget(outTargetInput.value));
outTargetInput?.addEventListener('input', () => {
  const preview = normalizeOutTarget(outTargetInput.value);
  const enabled = outCounterEnabledInput ? outCounterEnabledInput.checked : true;
  updateOutTargetHint(preview, enabled);
});
outTargetInput?.addEventListener('keydown', (e) => {
  if (e.key === 'Enter') {
    e.preventDefault();
    outTargetInput.blur();
    saveOutTarget(outTargetInput.value);
  }
});
async function downloadUnifiedBackup() {
  try {
    await window.ChillicollectivoUnifiedBackup?.download?.();
    showToast('Backup heruntergeladen');
    showBackupStatus('Backup heruntergeladen.');
  } catch (error) {
    showBackupStatus(error?.message || 'Backup konnte nicht erstellt werden.', true);
    showToast('Backup fehlgeschlagen');
  }
}

async function importUnifiedBackupFromFile(file) {
  if (!file) return;
  try {
    await window.ChillicollectivoUnifiedBackup.importFile(file, {
      normalizeChiliStimmung: window.chillicollectivoNormalizeChiliStimmungBackup,
    });
    await loadSettings();
    showToast('Backup geladen');
    showBackupStatus('Backup geladen. Extension neu laden empfohlen.');
  } catch (error) {
    showBackupStatus(error?.message || 'Backup konnte nicht geladen werden.', true);
    showToast('Backup laden fehlgeschlagen');
  } finally {
    const input = document.getElementById('unifiedBackupFile');
    if (input) input.value = '';
  }
}

document.getElementById('downloadUnifiedBackup')?.addEventListener('click', () => downloadUnifiedBackup());
document.getElementById('uploadUnifiedBackup')?.addEventListener('click', () => document.getElementById('unifiedBackupFile')?.click());
document.getElementById('unifiedBackupFile')?.addEventListener('change', (event) => {
  importUnifiedBackupFromFile(event.target.files?.[0]);
});

document.getElementById('exportDiagnosticLog')?.addEventListener('click', () => exportDiagnosticLog());
document.getElementById('clearDiagnosticLog')?.addEventListener('click', () => clearDiagnosticLog());
document.getElementById('exportVoiceMessageLog')?.addEventListener('click', () => exportVoiceMessageLog());
document.getElementById('clearVoiceMessageLog')?.addEventListener('click', () => clearVoiceMessageLog());

const ZERO_COINS_DAYTIME_BLOCK_STORAGE_KEY = 'torchwoodZeroCoinsDaytimeBlock';
let zeroCoinsDaytimeBlockEnabled = true;

function loadZeroCoinsDaytimeBlockSetting() {
  chrome.storage.local.get(ZERO_COINS_DAYTIME_BLOCK_STORAGE_KEY, (data) => {
    zeroCoinsDaytimeBlockEnabled = data[ZERO_COINS_DAYTIME_BLOCK_STORAGE_KEY] === true;
    const toggleEl = document.getElementById('zeroCoinsDaytimeBlock');
    if (toggleEl) toggleEl.checked = zeroCoinsDaytimeBlockEnabled;
    updateZeroCoinsDaytimeNotice();
  });
}

function saveZeroCoinsDaytimeBlockSetting() {
  const toggleEl = document.getElementById('zeroCoinsDaytimeBlock');
  zeroCoinsDaytimeBlockEnabled = toggleEl?.checked === true;
  chrome.storage.local.set({
    [ZERO_COINS_DAYTIME_BLOCK_STORAGE_KEY]: zeroCoinsDaytimeBlockEnabled,
  });
  updateZeroCoinsDaytimeNotice();
}

document.getElementById('zeroCoinsDaytimeBlock')?.addEventListener('change', saveZeroCoinsDaytimeBlockSetting);
loadZeroCoinsDaytimeBlockSetting();

function isLocalDaytimeBlockedForLowCoins() {
  const now = new Date();
  const sec = now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds();
  return sec >= 2 * 3600 && sec < 8 * 3600;
}

function updateZeroCoinsDaytimeNotice() {
  const el = document.getElementById('zeroCoinsDaytimeNotice');
  if (!el) return;
  if (!zeroCoinsDaytimeBlockEnabled) {
    el.textContent = 'Zeitsperre ist aus — Coin-Bilder sind auch zwischen 02:00 und 08:00 möglich (wenn im Powertool-Menü eingeschaltet).';
    el.classList.remove('is-warning');
    return;
  }
  const blocked = isLocalDaytimeBlockedForLowCoins();
  if (blocked) {
    el.textContent = 'Gerade AUS (02:00–08:00): Tagsüber besteht FSK+0-Bild-Risiko – die Coin-Auto-Bild-Funktion ist in dieser Zeit automatisch deaktiviert.';
    el.classList.add('is-warning');
  } else {
    el.textContent = 'Aktiv ab 08:00 Uhr (wenn im Powertool-Menü eingeschaltet). Zwischen 02:00 und 08:00 automatisch AUS wegen Tagsüber-Bild-Risiko.';
    el.classList.remove('is-warning');
  }
}

updateZeroCoinsDaytimeNotice();
window.setInterval(updateZeroCoinsDaytimeNotice, 30000);

function fillGalleryCommandForm(cfg) {
  const c = cfg || (typeof chillicollectivoGetDefaultGalleryCmdConfig === 'function' ? chillicollectivoGetDefaultGalleryCmdConfig() : {});
  const enabledEl = document.getElementById('galleryCmdEnabled');
  const fskEl = document.getElementById('galleryFsk18Triggers');
  const fsk0El = document.getElementById('galleryFsk0Triggers');
  const openEl = document.getElementById('galleryOpenTriggers');
  const sectionsEl = document.getElementById('gallerySearchSections');
  const autoConfirmEl = document.getElementById('galleryAutoConfirm');
  const skipSentEl = document.getElementById('gallerySkipSent');
  if (enabledEl) enabledEl.checked = c.enabled !== false;
  if (fskEl) fskEl.value = c.fsk18Triggers || '';
  if (fsk0El) fsk0El.value = c.fsk0Triggers || '';
  if (openEl) openEl.value = c.openGalleryTriggers || '';
  if (sectionsEl) sectionsEl.value = c.searchSections || '';
  if (skipSentEl) skipSentEl.checked = c.skipSent !== false;
  if (autoConfirmEl) autoConfirmEl.checked = c.autoConfirm !== false;
}

function readGalleryCommandForm() {
  return {
    enabled: document.getElementById('galleryCmdEnabled')?.checked !== false,
    fsk18Triggers: document.getElementById('galleryFsk18Triggers')?.value.trim() || '',
    fsk0Triggers: document.getElementById('galleryFsk0Triggers')?.value.trim() || '',
    openGalleryTriggers: document.getElementById('galleryOpenTriggers')?.value.trim() || '',
    searchSections: document.getElementById('gallerySearchSections')?.value.trim() || '',
    skipSent: document.getElementById('gallerySkipSent')?.checked !== false,
    autoConfirm: document.getElementById('galleryAutoConfirm')?.checked !== false,
  };
}

async function loadGalleryCommandConfig() {
  const data = await chrome.storage.local.get('chillicollectivoGalleryCommandConfig');
  const raw = data.chillicollectivoGalleryCommandConfig || null;
  const cfg = typeof chillicollectivoApplyGalleryCmdConfig === 'function'
    ? chillicollectivoApplyGalleryCmdConfig(raw)
    : raw;
  galleryCmdConfig = cfg;
  fillGalleryCommandForm(cfg || (typeof chillicollectivoGetDefaultGalleryCmdConfig === 'function' ? chillicollectivoGetDefaultGalleryCmdConfig() : {}));
  galleryCmdHydrated = true;
}

async function saveGalleryCommandConfig() {
  if (!galleryCmdHydrated) return;
  const payload = readGalleryCommandForm();
  galleryCmdConfig = typeof chillicollectivoApplyGalleryCmdConfig === 'function'
    ? chillicollectivoApplyGalleryCmdConfig(payload)
    : payload;
  await chrome.storage.local.set({ chillicollectivoGalleryCommandConfig: galleryCmdConfig });
  showToast();
}

async function resetGalleryCommandConfig() {
  const defaults = typeof chillicollectivoGetDefaultGalleryCmdConfig === 'function'
    ? chillicollectivoGetDefaultGalleryCmdConfig()
    : {};
  galleryCmdConfig = typeof chillicollectivoApplyGalleryCmdConfig === 'function'
    ? chillicollectivoApplyGalleryCmdConfig(defaults)
    : defaults;
  await chrome.storage.local.set({ chillicollectivoGalleryCommandConfig: galleryCmdConfig });
  fillGalleryCommandForm(galleryCmdConfig);
  showToast();
}

[
  'galleryFsk18Triggers',
  'galleryFsk0Triggers',
  'galleryOpenTriggers',
  'gallerySearchSections',
].forEach((id) => {
  const el = document.getElementById(id);
  if (!el) return;
  el.addEventListener('change', () => saveGalleryCommandConfig());
  el.addEventListener('blur', () => saveGalleryCommandConfig());
});

document.getElementById('galleryCmdEnabled')?.addEventListener('change', () => saveGalleryCommandConfig());
document.getElementById('gallerySkipSent')?.addEventListener('change', () => saveGalleryCommandConfig());
document.getElementById('galleryAutoConfirm')?.addEventListener('change', () => saveGalleryCommandConfig());
document.getElementById('galleryCmdReset')?.addEventListener('click', () => resetGalleryCommandConfig());

const INOUT_QUOTE_KEYS = {
  enabled: 'inoutQuoteEnabled',
  allowedSites: 'inoutQuoteAllowedSites',
  state: 'inoutQuoteV24State',
  calib: 'inoutQuoteV24Calib',
  lastGood: 'inoutQuoteV24LastGood',
  pos: 'inoutQuoteV24Pos',
};

function parseInoutQuoteAllowedSitesRaw(raw) {
  return String(raw || '')
    .split(/\r?\n/)
    .map((line) => line.trim())
    .filter(Boolean);
}

function formatInoutQuoteAllowedSitesList(list) {
  return Array.isArray(list) ? list.join('\n') : '';
}

async function loadInoutQuoteSettings() {
  const data = await chrome.storage.local.get([
    INOUT_QUOTE_KEYS.enabled,
    INOUT_QUOTE_KEYS.allowedSites,
  ]);
  const enabledEl = document.getElementById('inoutQuoteEnabled');
  const sitesEl = document.getElementById('inoutQuoteAllowedSites');
  if (enabledEl) enabledEl.checked = data[INOUT_QUOTE_KEYS.enabled] !== false;
  if (sitesEl) {
    sitesEl.value = formatInoutQuoteAllowedSitesList(data[INOUT_QUOTE_KEYS.allowedSites]);
  }
}

async function saveInoutQuoteSettings() {
  const enabledEl = document.getElementById('inoutQuoteEnabled');
  const sitesEl = document.getElementById('inoutQuoteAllowedSites');
  await chrome.storage.local.set({
    [INOUT_QUOTE_KEYS.enabled]: enabledEl ? enabledEl.checked : true,
    [INOUT_QUOTE_KEYS.allowedSites]: parseInoutQuoteAllowedSitesRaw(sitesEl?.value || ''),
  });
  showToast();
}

document.getElementById('inoutQuoteEnabled')?.addEventListener('change', () => saveInoutQuoteSettings());
document.getElementById('inoutQuoteAllowedSites')?.addEventListener('blur', () => saveInoutQuoteSettings());

document.getElementById('inoutQuoteResetCalib')?.addEventListener('click', async () => {
  await chrome.storage.local.remove([
    INOUT_QUOTE_KEYS.calib,
    INOUT_QUOTE_KEYS.lastGood,
    INOUT_QUOTE_KEYS.state,
  ]);
  showToast();
});

document.getElementById('inoutQuoteResetTimer')?.addEventListener('click', async () => {
  await chrome.storage.local.remove([INOUT_QUOTE_KEYS.state]);
  showToast();
});

document.getElementById('inoutQuoteResetPos')?.addEventListener('click', async () => {
  await chrome.storage.local.remove([INOUT_QUOTE_KEYS.pos]);
  showToast();
});

window.ChillicollectivoVoiceSmileysOptions?.init?.(() => {
  if (!settingsHydrated) return;
  saveSettings();
});

window.ChillicollectivoVoiceCorrectionsOptions?.init?.(() => {
  if (!settingsHydrated) return;
  saveSettings();
});

function openChiliStimmungSection() {
  const section = document.getElementById('chiliStimmungSection');
  section?.setAttribute('open', '');
  section?.scrollIntoView({ behavior: 'smooth', block: 'start' });
}

async function setChiliStimmungEnabled(enabled) {
  const patch = { [CHILLICOLLECTIVO_CHILI_STIMMUNG_ENABLED_KEY]: enabled === true };
  await new Promise((resolve) => chrome.storage.local.set(patch, resolve));

  const data = await new Promise((resolve) => {
    chrome.storage.local.get([
      CHILLICOLLECTIVO_CHILI_STIMMUNG_SETTINGS_KEY,
      CHILLICOLLECTIVO_CHILI_STIMMUNG_SETTINGS_LEGACY_KEY,
    ], (stored) => resolve(stored || {}));
  });
  let current = data[CHILLICOLLECTIVO_CHILI_STIMMUNG_SETTINGS_KEY];
  if (!current && data[CHILLICOLLECTIVO_CHILI_STIMMUNG_SETTINGS_LEGACY_KEY]) {
    current = data[CHILLICOLLECTIVO_CHILI_STIMMUNG_SETTINGS_LEGACY_KEY];
  }
  current = current || {};
  await new Promise((resolve) => {
    chrome.storage.local.set({
      [CHILLICOLLECTIVO_CHILI_STIMMUNG_SETTINGS_KEY]: {
        ...current,
        enabled: enabled === true,
      },
    }, resolve);
  });
}

function syncChiliStimmungSection() {
  const toggle = document.getElementById('chiliStimmungEnabled');
  const editBtn = document.getElementById('openChiliStimmungOptions');
  chrome.storage.local.get([CHILLICOLLECTIVO_CHILI_STIMMUNG_ENABLED_KEY], (data) => {
    const enabled = data?.[CHILLICOLLECTIVO_CHILI_STIMMUNG_ENABLED_KEY] !== false;
    if (toggle) {
      toggle.disabled = false;
      toggle.checked = enabled;
    }
    if (editBtn) editBtn.disabled = false;
  });
}

function initChiliStimmungSection() {
  document.getElementById('chiliStimmungEnabled')?.addEventListener('change', async (e) => {
    const enabled = e.target?.checked === true;
    await setChiliStimmungEnabled(enabled);
    showToast(enabled ? 'Chili-Stimmung aktiviert' : 'Chili-Stimmung deaktiviert');
  });

  document.getElementById('openChiliStimmungOptions')?.addEventListener('click', openChiliStimmungOptionsPage);

  if (typeof chillicollectivoEnsureChiliStimmungDefaults === 'function') {
    chillicollectivoEnsureChiliStimmungDefaults().then(syncChiliStimmungSection).catch(syncChiliStimmungSection);
  } else {
    chrome.storage.local.get([CHILLICOLLECTIVO_CHILI_STIMMUNG_ENABLED_KEY], (data) => {
      if (data?.[CHILLICOLLECTIVO_CHILI_STIMMUNG_ENABLED_KEY] === undefined) {
        setChiliStimmungEnabled(true).then(syncChiliStimmungSection);
        return;
      }
      syncChiliStimmungSection();
    });
  }
}

function openChiliStimmungOptionsPage() {
  window.location.href = chrome.runtime.getURL('chillistimmung-options.html');
}

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

function renderExtensionVersionFooter() {
  const notice = document.getElementById('extensionVersionNotice');
  if (!notice) return;
  notice.textContent = `ChiliColectivo AgentenMic ${getInstalledExtensionVersion()}`;
}

function applyMicUpdateDownloadButtons(info) {
  const downloads = typeof chillicollectivoResolveMicUpdateDownloads === 'function'
    ? chillicollectivoResolveMicUpdateDownloads(info)
    : [];
  const latest = downloads.find((entry) => entry.role === 'latest') || downloads[0] || null;
  const previous = downloads.find((entry) => entry.role === 'previous') || downloads[1] || null;
  const showDownloads = !!info?.outdated && downloads.length > 0;
  const pairs = [
    ['micUpdateDownloadLatest', latest],
    ['micUpdateDownloadLatestTop', latest],
    ['micUpdateDownloadPrevious', previous],
    ['micUpdateDownloadPreviousTop', previous],
  ];
  for (const [id, entry] of pairs) {
    const button = document.getElementById(id);
    if (!button) continue;
    const isPrevious = id === 'micUpdateDownloadPrevious' || id === 'micUpdateDownloadPreviousTop';
    const activeEntry = isPrevious ? previous : latest;
    const visible = showDownloads && !!activeEntry?.url;
    button.classList.toggle('hidden', !visible);
    if (!visible) continue;
    const versionLabel = activeEntry.version ? ` (${activeEntry.version})` : '';
    const label = activeEntry.label || (isPrevious ? 'Vorherige Version' : 'Neueste Version');
    button.textContent = `${label} laden${versionLabel}`;
    button.dataset.downloadUrl = activeEntry.url;
  }
}

function renderMicUpdateUi(info) {
  const current = getInstalledExtensionVersion();
  const currentEl = document.getElementById('micUpdateCurrentVersion');
  if (currentEl) currentEl.textContent = current;

  const outdated = !!info?.outdated;
  const needsUpgrade = outdated || !!info?.updateRequired;
  const updateSection = document.getElementById('updateSection');
  if (updateSection) {
    updateSection.classList.toggle('options-collapse-update-shiny', needsUpgrade);
  }

  const statusText = document.getElementById('micUpdateStatusText');
  if (statusText) {
    if (!info) {
      statusText.textContent = 'Update-Status wird geprüft …';
    } else if (!outdated) {
      statusText.textContent = `Aktuelle Version geladen (${info.latest || current}).`;
    } else {
      const downloads = typeof chillicollectivoResolveMicUpdateDownloads === 'function'
        ? chillicollectivoResolveMicUpdateDownloads(info)
        : [];
      const previous = downloads.find((entry) => entry.role === 'previous');
      statusText.textContent = previous
        ? `${info.message || `Version ${info.latest} ist verfügbar.`} Auch Version ${previous.version} steht bereit.`
        : (info.message || `Version ${info.latest} ist verfügbar.`);
    }
  }

  const hintEl = document.getElementById('micUpdateHint');
  if (hintEl) {
    const hint = info?.downloadHint || '';
    hintEl.textContent = hint;
    hintEl.classList.toggle('hidden', !hint || !outdated);
  }

  applyMicUpdateDownloadButtons(info);

  const banner = document.getElementById('micUpdateBanner');
  const text = document.getElementById('micUpdateBannerText');
  const hint = document.getElementById('micUpdateBannerHint');
  if (!banner || !text) return;
  if (!outdated) {
    banner.classList.add('hidden');
    banner.classList.remove('is-required');
    return;
  }
  banner.classList.remove('hidden');
  banner.classList.toggle('is-required', !!info.updateRequired);
  const title = banner.querySelector('.mic-update-banner-title');
  if (title) {
    title.textContent = info.updateRequired ? 'Mic-Update erforderlich' : 'Neue Mic-Version verfügbar';
  }
  text.textContent = info.message || (
    info.updateRequired
      ? `Bitte Version ${info.min || info.latest || 'neu'} installieren.`
      : `Version ${info.latest || 'neu'} ist verfügbar.`
  );
  if (hint) {
    hint.textContent = info.downloadHint || 'ZIP laden, Ordner ersetzen, Extension in Chrome neu laden.';
  }
}

function renderMicUpdateBanner(info) {
  renderMicUpdateUi(info);
}

async function refreshMicUpdateBanner() {
  try {
    const info = await (chillicollectivoGetMicUpdateInfo?.() || Promise.resolve(null));
    renderMicUpdateBanner(info);
  } catch (_) {}
}

async function checkMicUpdateFromServer() {
  const info = await (chillicollectivoFetchMicUpdateFromServer?.() || Promise.resolve(null));
  renderMicUpdateBanner(info);
  return info;
}

function initMicVersionUi() {
  renderExtensionVersionFooter();
  void refreshMicUpdateBanner();
  void (chillicollectivoFetchMicUpdateFromServer?.().then((info) => renderMicUpdateBanner(info)).catch(() => {}));
  chrome.storage.onChanged.addListener((changes, area) => {
    if (area !== 'local') return;
    if (changes.chillicollectivoMicUpdate) {
      renderMicUpdateBanner(changes.chillicollectivoMicUpdate.newValue || null);
    }
  });
  document.getElementById('micUpdateCheckBtnTop')?.addEventListener('click', () => {
    checkMicUpdateFromServer()
      .then((info) => {
        showToast(info?.outdated ? `Update verfügbar: Version ${info.latest}` : 'Du hast die neueste Version.');
      })
      .catch(() => showToast('Update-Check fehlgeschlagen'));
  });
  document.getElementById('micUpdateCheckBtn')?.addEventListener('click', () => {
    const btn = document.getElementById('micUpdateCheckBtn');
    if (btn) btn.disabled = true;
    checkMicUpdateFromServer()
      .then((info) => {
        showToast(info?.outdated ? `Update verfügbar: Version ${info.latest}` : `Aktuelle Version geladen (${info?.latest || getInstalledExtensionVersion()}).`);
      })
      .catch(() => showToast('Update-Check fehlgeschlagen'))
      .finally(() => {
        if (btn) btn.disabled = false;
      });
  });
  for (const id of ['micUpdateDownloadLatestTop', 'micUpdateDownloadPreviousTop', 'micUpdateDownloadLatest', 'micUpdateDownloadPrevious']) {
    document.getElementById(id)?.addEventListener('click', async (event) => {
      const url = event.currentTarget?.dataset?.downloadUrl || '';
      let info = await chillicollectivoGetMicUpdateInfo?.();
      if (!url) {
        info = await checkMicUpdateFromServer();
      }
      if (!chillicollectivoOpenMicUpdateDownload?.(info, url)) {
        showToast('Kein Download-Link auf dem Server hinterlegt.');
        return;
      }
      showToast('Download wird geöffnet …');
    });
  }
}

loadSettings();
initMicVersionUi();
initLicensePanel();

function initLicensePanel() {
  const badge = document.getElementById('licenseStatusBadge');
  const statusText = document.getElementById('licenseStatusText');
  const licenseCountdownBox = document.getElementById('licenseCountdownBox');
  const licenseCountdownLabel = document.getElementById('licenseCountdownLabel');
  const licenseCountdownValue = document.getElementById('licenseCountdownValue');
  const keyInput = document.getElementById('licenseKeyInput');
  const emailInput = document.getElementById('licenseEmailInput');
  const activateBtn = document.getElementById('licenseActivateBtn');
  const buyBtn = document.getElementById('licenseBuyBtn');
  const clearBtn = document.getElementById('licenseClearBtn');
  let licenseCounterTimer = null;
  if (!badge || !statusText) return;

  function stopLicenseCounter() {
    if (licenseCounterTimer) {
      clearInterval(licenseCounterTimer);
      licenseCounterTimer = null;
    }
  }

  function applyCountdownTone(tone) {
    if (!licenseCountdownBox) return;
    licenseCountdownBox.classList.remove('tone-active', 'tone-bonus', 'tone-trial');
    if (tone === 'active') licenseCountdownBox.classList.add('tone-active');
    else if (tone === 'bonus') licenseCountdownBox.classList.add('tone-bonus');
    else licenseCountdownBox.classList.add('tone-trial');
  }

  function updateLicenseCountdown(state) {
    stopLicenseCounter();
    if (!licenseCountdownBox || !licenseCountdownValue || !licenseCountdownLabel) return;

    const countdown = typeof chillicollectivoResolveLicenseCountdown === 'function'
      ? chillicollectivoResolveLicenseCountdown(state)
      : null;

    if (!countdown) {
      licenseCountdownBox.classList.add('hidden');
      return;
    }

    licenseCountdownLabel.textContent = countdown.label || 'Lizenz – noch';
    applyCountdownTone(countdown.tone || 'active');
    licenseCountdownBox.classList.remove('hidden');

    if (countdown.mode === 'static') {
      licenseCountdownValue.textContent = countdown.staticValue || '—';
      return;
    }

    const anchor = Date.now();
    const initial = Number(countdown.remainingMs || 0);
    const formatValue = (remaining) => (
      (state?.reason === 'trial' && state?.license?.valid !== true)
        || (typeof chillicollectivoCountdownUsesClockFormat === 'function'
          && chillicollectivoCountdownUsesClockFormat(remaining, state))
        ? chillicollectivoFormatTrialCountdown(remaining)
        : chillicollectivoFormatLicenseCountdown(remaining)
    );

    const renderRemaining = () => {
      const remaining = Math.max(0, initial - (Date.now() - anchor));
      licenseCountdownValue.textContent = formatValue(remaining);
      return remaining;
    };

    renderRemaining();
    const intervalMs = initial < 60 * 60 * 1000 ? 250 : 1000;
    licenseCounterTimer = setInterval(async () => {
      const remaining = renderRemaining();
      if (remaining <= 0) {
        stopLicenseCounter();
        licenseCountdownBox.classList.add('hidden');
        await refreshLicenseState(false);
      }
    }, intervalMs);
  }

  function renderLicenseState(state) {
    badge.className = 'license-badge';
    if (state?.access === 'granted') {
      if (state.reason === 'preview') {
        badge.classList.add('license-badge-active');
        badge.textContent = 'Vorversion';
      } else if (state.reason === 'local_offline') {
        badge.classList.add('license-badge-active');
        badge.textContent = 'Offline';
      } else if (state.reason === 'out_reward') {
        badge.classList.add('license-badge-trial');
        badge.textContent = 'Out-Bonus';
      } else {
        badge.classList.add(state.reason === 'trial' ? 'license-badge-trial' : 'license-badge-active');
        badge.textContent = state.reason === 'trial' ? 'Testphase' : 'Aktiv';
      }
    } else if (state?.access === 'expired') {
      badge.classList.add('license-badge-expired');
      badge.textContent = 'Abgelaufen';
    } else {
      badge.classList.add('license-badge-locked');
      badge.textContent = 'Gesperrt';
    }
    statusText.textContent = state?.message || 'Kein Lizenzstatus';
    updateLicenseCountdown(state);
    if (keyInput && state?.license?.key) {
      keyInput.value = chillicollectivoFormatLicenseKeyInput(state.license.key);
    }
    const email = String(state?.license?.email || '').trim();
    if (email && emailInput && !emailInput.value) {
      emailInput.value = email;
    }
    chillicollectivoGetOutRewardRecord?.().then(renderOutRewardBanner).catch(() => {});
  }

  let licenseRefreshSeq = 0;
  let lastKnownLicenseAccess = null;

  function sendRuntimeMessage(message, timeoutMs = 12000) {
    return new Promise((resolve, reject) => {
      const timer = setTimeout(() => reject(new Error('Zeitüberschreitung bei der Lizenzprüfung')), timeoutMs);
      chrome.runtime.sendMessage(message, (response) => {
        clearTimeout(timer);
        if (chrome.runtime.lastError) {
          reject(new Error(chrome.runtime.lastError.message));
          return;
        }
        resolve(response);
      });
    });
  }

  function resolveLicensePanelState(license, state) {
    if (state) return state;
    if (license?.valid === true && typeof chillicollectivoBuildLicenseState === 'function') {
      return chillicollectivoBuildLicenseState(license, null);
    }
    return null;
  }

  function applyLicensePanelState(state) {
    if (!state) return;
    licenseRefreshSeq += 1;
    lastKnownLicenseAccess = state.access || null;
    renderLicenseState(state);
  }

  async function loadLocalLicensePanelState() {
    if (typeof chillicollectivoGetLicenseState !== 'function') return null;
    try {
      return await chillicollectivoGetLicenseState({
        revalidate: false,
        startTrial: false,
        scheduleWatch: false,
      });
    } catch (_) {
      return null;
    }
  }

  async function refreshLicenseState(revalidate = false) {
    const seq = ++licenseRefreshSeq;
    const localState = await loadLocalLicensePanelState();
    if (seq === licenseRefreshSeq && localState) {
      lastKnownLicenseAccess = localState.access || null;
      renderLicenseState(localState);
    }
    if (revalidate) {
      const showChecking = !localState || localState.access !== 'granted';
      if (seq === licenseRefreshSeq && showChecking) {
        badge.textContent = 'Wird geprüft …';
        badge.className = 'license-badge license-badge-unknown';
      }
    }
    try {
      const response = await sendRuntimeMessage(
        { type: 'GET_LICENSE_STATE', revalidate },
        revalidate ? 12000 : 8000,
      );
      if (seq !== licenseRefreshSeq) return null;
      if (response?.success && response.state) {
        lastKnownLicenseAccess = response.state.access || null;
        renderLicenseState(response.state);
        void refreshMicUpdateBanner();
        return response.state;
      }
      if (seq === licenseRefreshSeq && (!localState || localState.access !== 'granted')) {
        statusText.textContent = response?.error || 'Lizenzstatus konnte nicht geladen werden.';
        badge.classList.add('license-badge-locked');
        badge.textContent = 'Fehler';
      }
    } catch (e) {
      if (seq !== licenseRefreshSeq) return null;
      const fallback = localState || await loadLocalLicensePanelState();
      if (fallback) {
        lastKnownLicenseAccess = fallback.access || null;
        renderLicenseState(fallback);
        return fallback;
      }
      if (lastKnownLicenseAccess !== 'granted') {
        statusText.textContent = e?.message || 'Lizenzstatus konnte nicht geladen werden.';
        badge.classList.add('license-badge-locked');
        badge.textContent = 'Fehler';
      }
    }
    return null;
  }

  keyInput?.addEventListener('input', () => {
    const pos = keyInput.selectionStart;
    keyInput.value = chillicollectivoFormatLicenseKeyInput(keyInput.value);
    if (typeof pos === 'number') keyInput.setSelectionRange(keyInput.value.length, keyInput.value.length);
  });

  activateBtn?.addEventListener('click', async () => {
    const key = keyInput?.value?.trim();
    const email = String(emailInput?.value || '').trim().toLowerCase();
    if (!email) {
      showToast('Bitte E-Mail eingeben');
      emailInput?.focus();
      return;
    }
    if (!key) {
      showToast('Bitte Lizenzschlüssel eingeben');
      return;
    }
    activateBtn.disabled = true;
    try {
      const response = await sendRuntimeMessage({ type: 'ACTIVATE_LICENSE', key, email }, 15000);
      if (!response?.success) throw new Error(response?.error || 'Aktivierung fehlgeschlagen');
      applyLicensePanelState(resolveLicensePanelState(response.license, response.state));
      showToast('Lizenz aktiviert');
    } catch (e) {
      showToast(e?.message || 'Aktivierung fehlgeschlagen');
      await refreshLicenseState(false);
    } finally {
      activateBtn.disabled = false;
    }
  });

  buyBtn?.addEventListener('click', () => {
    chrome.runtime.sendMessage({ type: 'OPEN_SALES_PAGE' });
  });

  clearBtn?.addEventListener('click', async () => {
    clearBtn.disabled = true;
    try {
      const response = await chrome.runtime.sendMessage({ type: 'CLEAR_LICENSE' });
      if (keyInput) keyInput.value = '';
      if (emailInput) emailInput.value = '';
      if (response?.state) applyLicensePanelState(response.state);
      else await refreshLicenseState(false);
      showToast('Lizenz entfernt');
    } finally {
      clearBtn.disabled = false;
    }
  });

  if (location.hash === '#license') {
    document.getElementById('licenseSection')?.setAttribute('open', '');
    document.getElementById('licenseSection')?.scrollIntoView({ behavior: 'smooth', block: 'start' });
  }

  void refreshLicenseState(false).then(() => refreshLicenseState(true));

  chrome.storage.onChanged.addListener((changes, area) => {
    if (area !== 'local') return;
    if (changes.chillicollectivoLicense || changes.chillicollectivoTrialStartedAt) {
      loadLocalLicensePanelState().then((state) => {
        if (state) applyLicensePanelState(state);
      });
    }
  });

  chrome.runtime.onMessage.addListener((message) => {
    if (message?.type === 'LICENSE_STATE' && message.state) {
      applyLicensePanelState(message.state);
    }
  });
}
if (document.getElementById('galleryCmdEnabled')) loadGalleryCommandConfig();
if (document.getElementById('inoutQuoteEnabled')) loadInoutQuoteSettings();
loadOutCounterStatus();
if (voiceMessageLogPreview) refreshVoiceMessageLogStatus();

chrome.storage.onChanged.addListener((changes, area) => {
  if (area !== 'local') return;
  if (changes[CHILLICOLLECTIVO_OUT_COUNTER_KEY] || changes[CHILLICOLLECTIVO_OUT_TARGET_KEY] || changes[CHILLICOLLECTIVO_OUT_COUNTER_TOTAL_KEY] || changes[CHILLICOLLECTIVO_OUT_COUNTER_ENABLED_KEY] || changes.chillicollectivoOutReward) {
    chrome.storage.local.get([
      CHILLICOLLECTIVO_OUT_COUNTER_KEY,
      CHILLICOLLECTIVO_OUT_TARGET_KEY,
      CHILLICOLLECTIVO_OUT_COUNTER_TOTAL_KEY,
      CHILLICOLLECTIVO_OUT_COUNTER_ENABLED_KEY,
    ], async (data) => {
      const target = normalizeOutTarget(data?.[CHILLICOLLECTIVO_OUT_TARGET_KEY]);
      const enabled = data?.[CHILLICOLLECTIVO_OUT_COUNTER_ENABLED_KEY] !== false;
      if (changes[CHILLICOLLECTIVO_OUT_COUNTER_ENABLED_KEY]) syncOutCounterEnabledUi(enabled);
      if (changes[CHILLICOLLECTIVO_OUT_TARGET_KEY] && outTargetInput) {
        outTargetInput.value = formatOutTargetInputValue(target);
        updateOutTargetHint(target, enabled);
      }
      renderOutCounterStatus(data?.[CHILLICOLLECTIVO_OUT_COUNTER_KEY], target);
      const reward = await chillicollectivoGetOutRewardRecord?.().catch(() => null);
      renderOutTotalHint(data?.[CHILLICOLLECTIVO_OUT_COUNTER_TOTAL_KEY], reward);
      renderOutRewardBanner(reward);
    });
  }
  if (changes[CHILLICOLLECTIVO_CHILI_STIMMUNG_ENABLED_KEY]) {
    syncChiliStimmungSection();
  }
  if (changes[ZERO_COINS_DAYTIME_BLOCK_STORAGE_KEY]) {
    zeroCoinsDaytimeBlockEnabled = changes[ZERO_COINS_DAYTIME_BLOCK_STORAGE_KEY].newValue === true;
    const toggleEl = document.getElementById('zeroCoinsDaytimeBlock');
    if (toggleEl) toggleEl.checked = zeroCoinsDaytimeBlockEnabled;
    updateZeroCoinsDaytimeNotice();
  }
  if (changes[VOICE_MESSAGE_LOG_STORAGE_KEY]) {
    refreshVoiceMessageLogStatus();
  }
});
