/// Vault-level settings screen. Covers retention (trash + field history),
/// generator defaults (preview + "configure" → opens popover), and
/// autofill origin-ack revocation.

import { getState, setState, sendMessage, navigate, escapeHtml, openVaultTab } from '../../shared/state';
import type {
  VaultSettings, TrashRetention, HistoryRetention, GeneratorRequest,
} from '../../shared/types';
import type { SessionTimeoutConfig } from '../../shared/messages';
import { relativeTime } from '../../shared/relative-time';
import { openGeneratorPanel, closeGeneratorPanel, isGeneratorPanelOpen } from './generator-panel';
import { teardownSettingsCommon } from './settings';
import { GLYPH_NEXT } from '../../shared/glyphs';

let pendingSettings: VaultSettings | null = null;
let activeKeyHandler: ((e: KeyboardEvent) => void) | null = null;
let pendingSession: SessionTimeoutConfig | null = null;
let baseSession: SessionTimeoutConfig | null = null;

export function teardown(): void {
  activeKeyHandler = teardownSettingsCommon(activeKeyHandler);
  pendingSettings = null;
  pendingSession = null;
  baseSession = null;
}

// --- Retention helpers ---

function trashRetentionToValue(r: TrashRetention): string {
  if (r.kind === 'forever') return 'forever';
  return `days:${r.value}`;
}

function valueToTrashRetention(v: string): TrashRetention {
  if (v === 'forever') return { kind: 'forever' };
  const m = /^days:(\d+)$/.exec(v);
  if (m) return { kind: 'days', value: Number(m[1]) };
  return { kind: 'forever' };
}

function historyRetentionToValue(r: HistoryRetention): string {
  if (r.kind === 'forever') return 'forever';
  if (r.kind === 'last_n') return `last_n:${r.value}`;
  return `days:${r.value}`;
}

function valueToHistoryRetention(v: string): HistoryRetention {
  if (v === 'forever') return { kind: 'forever' };
  const mLast = /^last_n:(\d+)$/.exec(v);
  if (mLast) return { kind: 'last_n', value: Number(mLast[1]) };
  const mDays = /^days:(\d+)$/.exec(v);
  if (mDays) return { kind: 'days', value: Number(mDays[1]) };
  return { kind: 'forever' };
}

// --- Generator summary ---

function generatorSummary(req: GeneratorRequest): string {
  if (req.kind === 'random') {
    const classes: string[] = [];
    if (req.classes.lower)   classes.push('lower');
    if (req.classes.upper)   classes.push('upper');
    if (req.classes.digits)  classes.push('digits');
    if (req.classes.symbols) classes.push('symbols');
    const sc = req.symbol_charset.kind;
    return `Random, ${req.length} chars, ${classes.join('+') || 'no classes'}, ${sc} symbols`;
  }
  return `BIP39, ${req.word_count} words, "${req.separator}" separator, ${req.capitalization}`;
}

// --- Render ---

export function renderVaultSettings(app: HTMLElement): void {
  const state = getState();
  const base = state.vaultSettings;
  if (!base) {
    app.innerHTML = `<div class="pad"><p class="muted">Vault settings not loaded yet.</p></div>`;
    return;
  }
  pendingSettings = JSON.parse(JSON.stringify(base)) as VaultSettings;

  sendMessage({ type: 'get_session_config' }).then((resp) => {
    // Guard against clobbering the user's in-flight edits if they tap a radio
    // before the SW responds — tiny window but real.
    if (resp.ok && !pendingSession) {
      baseSession = (resp.data as { config: SessionTimeoutConfig }).config;
      pendingSession = JSON.parse(JSON.stringify(baseSession)) as SessionTimeoutConfig;
      rerender();
    }
  });

  function rerender(): void {
    if (!pendingSettings) return;
    const acksEntries = Object.entries(pendingSettings.autofill_origin_acks)
      .sort(([, a], [, b]) => b - a);

    const dirty: boolean = JSON.stringify(pendingSettings) !== JSON.stringify(base)
      || !!(baseSession && JSON.stringify(pendingSession) !== JSON.stringify(baseSession));
    const subtitle = dirty ? 'unsaved · esc to cancel' : 'no changes';

    const sessionMode = pendingSession?.mode ?? 'inactivity';
    const sessionMinutes = pendingSession && pendingSession.mode === 'inactivity'
      ? pendingSession.minutes : 15;

    app.innerHTML = `
      <div class="pad">
        <div class="settings-header">
          <button class="btn" id="back-btn">← back</button>
          <h3 style="margin:0;">settings</h3>
          <span class="muted settings-header__sub">${escapeHtml(subtitle)}</span>
        </div>

        <div class="section-header">VAULT SETTINGS · synced</div>

        <div class="settings-grid">
          <div class="settings-section">
            <div class="settings-section__title">RETENTION</div>
            <div class="settings-row">
              <span class="settings-row__label">trash</span>
              <select id="trash-retention">
                <option value="forever">Forever</option>
                <option value="days:7">7 days</option>
                <option value="days:30">30 days</option>
                <option value="days:60">60 days</option>
                <option value="days:90">90 days</option>
                <option value="days:180">180 days</option>
                <option value="days:365">365 days</option>
              </select>
            </div>
            <div class="settings-row">
              <span class="settings-row__label">history</span>
              <select id="history-retention">
                <option value="forever">Forever</option>
                <option value="last_n:3">Last 3</option>
                <option value="last_n:5">Last 5</option>
                <option value="last_n:10">Last 10</option>
                <option value="days:30">30 days</option>
                <option value="days:90">90 days</option>
                <option value="days:365">365 days</option>
              </select>
            </div>
          </div>

          <div class="settings-section">
            <div class="settings-section__title">GENERATOR</div>
            <p class="gen-preview-line">${escapeHtml(generatorSummary(pendingSettings.generator_defaults))}</p>
            <button class="gen-trigger" id="configure-gen" type="button" title="configure generator defaults" aria-expanded="false">✨ configure</button>
          </div>
        </div>

        <div class="settings-section">
          <div class="settings-section__title">ATTACHMENTS</div>
          <div class="settings-row">
            <span class="settings-row__label">max size</span>
            <select id="attachment-cap">
              <option value="5242880">5 MB</option>
              <option value="10485760">10 MB</option>
              <option value="26214400">25 MB</option>
              <option value="52428800">50 MB</option>
            </select>
          </div>
        </div>

        <div class="settings-section">
          <div class="settings-section__title">AUTOFILL ORIGINS</div>
          ${acksEntries.length === 0
            ? `<p class="muted">No origins acknowledged yet.</p>`
            : acksEntries.map(([host, ts]) => `
              <div class="ack-row">
                <span class="ack-row__host">${escapeHtml(host)}</span>
                <span class="ack-row__meta">${escapeHtml(relativeTime(ts))}</span>
                <button class="glyph-btn" data-danger title="revoke" data-revoke="${escapeHtml(host)}">⊘</button>
              </div>
            `).join('')}
        </div>

        <div class="section-header">THIS DEVICE · local</div>

        <div class="settings-section">
          <div class="settings-section__title">SESSION</div>
          <div class="settings-row">
            <label><input type="radio" name="session-mode" value="every_time" ${sessionMode === 'every_time' ? 'checked' : ''}> lock every time</label>
          </div>
          <div class="settings-row">
            <label><input type="radio" name="session-mode" value="inactivity" ${sessionMode === 'inactivity' ? 'checked' : ''}> after inactivity</label>
            <select id="session-minutes" ${sessionMode !== 'inactivity' ? 'disabled' : ''}>
              <option value="5">5 min</option>
              <option value="15">15 min</option>
              <option value="30">30 min</option>
              <option value="60">60 min</option>
            </select>
          </div>
        </div>

        <div class="section-header">ACTIONS</div>

        <div class="settings-section">
          <div class="settings-row">
            <button class="btn" id="open-backup">Backup &amp; restore ${GLYPH_NEXT}</button>
            <button class="btn" id="open-import">Import from… ${GLYPH_NEXT}</button>
          </div>
        </div>

        <div class="settings-footer">
          <button class="btn" id="discard-btn">discard</button>
          <button class="btn btn-primary" id="save-btn" ${dirty ? '' : 'disabled'}>save changes</button>
        </div>
      </div>
    `;

    (document.getElementById('trash-retention') as HTMLSelectElement).value =
      trashRetentionToValue(pendingSettings.trash_retention);
    (document.getElementById('history-retention') as HTMLSelectElement).value =
      historyRetentionToValue(pendingSettings.field_history_retention);
    const capValue = pendingSettings.attachment_caps?.per_attachment_max_bytes ?? 10485760;
    (document.getElementById('attachment-cap') as HTMLSelectElement).value = String(capValue);
    (document.getElementById('session-minutes') as HTMLSelectElement).value = String(sessionMinutes);

    wireHandlers();
  }

  function wireHandlers(): void {
    document.getElementById('back-btn')?.addEventListener('click', () => navigate('list'));
    document.getElementById('discard-btn')?.addEventListener('click', () => navigate('list'));
    document.getElementById('open-backup')?.addEventListener('click', () => openVaultTab('backup'));
    document.getElementById('open-import')?.addEventListener('click', () => openVaultTab('import'));

    document.getElementById('trash-retention')?.addEventListener('change', (e) => {
      if (!pendingSettings) return;
      pendingSettings.trash_retention = valueToTrashRetention((e.target as HTMLSelectElement).value);
      rerender();
    });

    document.getElementById('history-retention')?.addEventListener('change', (e) => {
      if (!pendingSettings) return;
      pendingSettings.field_history_retention = valueToHistoryRetention((e.target as HTMLSelectElement).value);
      rerender();
    });

    document.getElementById('attachment-cap')?.addEventListener('change', (e) => {
      if (!pendingSettings) return;
      const bytes = Number((e.target as HTMLSelectElement).value);
      pendingSettings.attachment_caps = {
        ...pendingSettings.attachment_caps,
        per_attachment_max_bytes: bytes,
      };
      rerender();
    });

    document.querySelectorAll<HTMLButtonElement>('[data-revoke]').forEach((btn) => {
      btn.addEventListener('click', () => {
        if (!pendingSettings) return;
        const host = btn.dataset.revoke ?? '';
        delete pendingSettings.autofill_origin_acks[host];
        rerender();
      });
    });

    document.getElementById('configure-gen')?.addEventListener('click', (e) => {
      const trigger = e.currentTarget as HTMLElement;
      if (isGeneratorPanelOpen()) {
        closeGeneratorPanel();
        return;
      }
      const generatorSection = trigger.closest('.settings-section') as HTMLElement | null;
      if (!generatorSection || pendingSettings === null) return;
      openGeneratorPanel({
        parent: generatorSection,
        trigger,
        initial: pendingSettings.generator_defaults,
        context: 'configure-defaults',
      });
    });

    document.getElementById('save-btn')?.addEventListener('click', async () => {
      if (!pendingSettings) return;
      const resp = await sendMessage({ type: 'update_vault_settings', settings: pendingSettings });
      if (!resp.ok) {
        setState({ error: resp.error });
        return;
      }
      if (pendingSession && JSON.stringify(pendingSession) !== JSON.stringify(baseSession)) {
        const sessResp = await sendMessage({ type: 'update_session_config', config: pendingSession });
        if (!sessResp.ok) {
          setState({ error: sessResp.error });
          return;
        }
        baseSession = JSON.parse(JSON.stringify(pendingSession)) as SessionTimeoutConfig;
      }
      const refreshed = await sendMessage({ type: 'get_vault_settings' });
      if (refreshed.ok && refreshed.data) {
        const vs = (refreshed.data as { settings: VaultSettings }).settings;
        if (vs) {
          setState({ vaultSettings: vs, generatorDefaults: vs.generator_defaults });
        }
      }
      navigate('list');
    });

    document.querySelectorAll<HTMLInputElement>('input[name="session-mode"]').forEach((el) => {
      el.addEventListener('change', () => {
        const mode = (document.querySelector<HTMLInputElement>('input[name="session-mode"]:checked')?.value ?? 'inactivity') as 'every_time' | 'inactivity';
        if (mode === 'every_time') {
          pendingSession = { mode: 'every_time' };
        } else {
          const mins = Number((document.getElementById('session-minutes') as HTMLSelectElement).value);
          pendingSession = { mode: 'inactivity', minutes: mins };
        }
        rerender();
      });
    });

    document.getElementById('session-minutes')?.addEventListener('change', (e) => {
      const mins = Number((e.target as HTMLSelectElement).value);
      if (pendingSession?.mode === 'inactivity') {
        pendingSession = { mode: 'inactivity', minutes: mins };
        rerender();
      }
    });
  }

  rerender();

  const handler = (e: KeyboardEvent) => {
    if (e.key === 'Escape') {
      if (activeKeyHandler) document.removeEventListener('keydown', activeKeyHandler);
      activeKeyHandler = null;
      navigate('list');
    }
  };
  activeKeyHandler = handler;
  document.addEventListener('keydown', handler);
}
