import { updateOwnProfile } from '@chat-app/shared/auth';
import {
  changeLocale as changeLocaleI18n,
  SUPPORTED_LOCALES,
  type SupportedLocale,
} from '@chat-app/shared/i18n';
import { useEffect, useState } from 'react';
import { useTranslation } from 'react-i18next';

import { LockIcon } from '../components/icons';
import { useAuth } from '../context/AuthContext';
import { loadDevicePrivateKey, saveDevicePrivateKey } from '@chat-app/shared/auth';
import { exportDeviceKey, importDeviceKey } from '../lib/deviceBackup';
import { devLocalSecretStore } from '../lib/secretStore';
import {
  getPttSettings,
  keyCodeToLabel,
  type PttSettings,
  subscribePttSettings,
  updatePttSettings,
} from '../lib/pttSettings';
import {
  AUDIO_QUALITY_ORDER,
  type AudioQuality,
  type AudioSettings,
  getAudioQualityParams,
  getAudioSettings,
  subscribeAudioSettings,
  updateAudioSettings,
} from '../lib/audioSettings';
import {
  type CallE2EESettings,
  getCallE2EESettings,
  isE2EESupported,
  subscribeCallE2EESettings,
  updateCallE2EESettings,
} from '../lib/callE2EE';
import {
  getPresetParams,
  getScreenShareSettings,
  PRESET_ORDER,
  type ScreenSharePreset,
  type ScreenShareSettings,
  subscribeScreenShareSettings,
  updateScreenShareSettings,
} from '../lib/screenShareSettings';
import { supabase } from '../lib/supabase';

const LOCALE_LABELS: Record<SupportedLocale, string> = {
  en: 'English',
  de: 'Deutsch',
};

export function SettingsPage() {
  const { t, i18n } = useTranslation(['app', 'common', 'auth']);
  const { profile, device, refreshProfile, signOut } = useAuth();
  const [busy, setBusy] = useState(false);

  async function patchProfile(patch: Parameters<typeof updateOwnProfile>[1]) {
    setBusy(true);
    try {
      await updateOwnProfile(supabase, patch);
      await refreshProfile();
    } catch (err: unknown) {
      console.error('updateProfile failed', err);
    } finally {
      setBusy(false);
    }
  }

  async function handleLocaleChange(locale: SupportedLocale) {
    await changeLocaleI18n(locale);
    void patchProfile({ locale });
  }

  return (
    <div className="mx-auto flex max-w-3xl flex-col gap-6 px-6 py-8">
      <header className="mb-2">
        <h1 className="font-display text-2xl font-semibold tracking-tight text-white">
          {t('app:settings.title')}
        </h1>
      </header>

      {/* Account */}
      <Section title={t('app:settings.section_account')}>
        <Row label={t('auth:signed_in.username')} value={profile?.username ?? '—'} />
        <Row label={t('auth:signed_in.display_name')} value={profile?.displayName ?? '—'} />
        <Row label={t('auth:signed_in.email')} value={profile?.userId ?? '—'} mono />
      </Section>

      {/* Appearance */}
      <Section title={t('app:settings.section_appearance')}>
        <SettingRow label={t('app:settings.language')}>
          <div className="inline-flex rounded-lg border border-white/10 bg-ink-800 p-1">
            {SUPPORTED_LOCALES.map((locale) => {
              const active = (i18n.resolvedLanguage ?? i18n.language) === locale;
              return (
                <button
                  key={locale}
                  type="button"
                  disabled={busy}
                  onClick={() => void handleLocaleChange(locale)}
                  className={
                    'cursor-pointer rounded-md px-3 py-1.5 text-xs font-medium transition focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-400/40 ' +
                    (active
                      ? 'bg-brand-500/25 text-white ring-1 ring-brand-400/40'
                      : 'text-neutral-400 hover:text-neutral-200')
                  }
                >
                  {LOCALE_LABELS[locale]}
                </button>
              );
            })}
          </div>
        </SettingRow>
      </Section>

      {/* Privacy */}
      <Section title={t('app:settings.section_privacy')}>
        <Toggle
          label={t('app:settings.show_read_receipts')}
          hint={t('app:settings.show_read_receipts_hint')}
          checked={profile?.showReadReceipts ?? true}
          disabled={busy || !profile}
          onChange={(v) => void patchProfile({ showReadReceipts: v })}
        />
        <Toggle
          label={t('app:settings.allow_dms_strangers')}
          hint={t('app:settings.allow_dms_strangers_hint')}
          checked={profile?.allowDmsFromStrangers ?? true}
          disabled={busy || !profile}
          onChange={(v) => void patchProfile({ allowDmsFromStrangers: v })}
        />
      </Section>

      {/* Voice / Push-to-Talk + Audio Quality + E2EE */}
      <Section title={t('app:settings.section_voice', { defaultValue: 'Sprache' })}>
        <AudioQualityControls />
        <div className="mt-3 border-t border-white/5 pt-3">
          <PttControls />
        </div>
        <div className="mt-3 border-t border-white/5 pt-3">
          <CallE2EEControls />
        </div>
      </Section>

      {/* Screen-share quality */}
      <Section title={t('app:settings.section_screen_share', { defaultValue: 'Bildschirmfreigabe' })}>
        <ScreenShareControls />
      </Section>

      {/* Devices */}
      <Section title={t('app:settings.section_devices')}>
        {device && (
          <div className="rounded-xl border border-emerald-500/20 bg-emerald-500/5 p-4">
            <div className="flex items-center gap-2 text-sm font-semibold text-emerald-200">
              <LockIcon className="h-4 w-4" />
              {t('app:settings.this_device')}
            </div>
            <dl className="mt-3 space-y-1.5 text-xs">
              <Row label={t('auth:signed_in.display_name')} value={device.name} />
              <Row label={t('auth:signed_in.device_platform')} value={device.platform} />
              <Row label={t('auth:signed_in.user_id')} value={device.id} mono />
            </dl>
          </div>
        )}
        <DeviceKeyBackupControls />
      </Section>

      {/* Danger zone */}
      <Section title={t('app:settings.danger_zone')}>
        <button
          type="button"
          onClick={() => void signOut()}
          className="cursor-pointer rounded-lg border border-rose-500/30 bg-rose-500/10 px-4 py-2.5 text-sm font-semibold text-rose-200 transition hover:bg-rose-500/20 focus:outline-none focus-visible:ring-2 focus-visible:ring-rose-400/50"
        >
          {t('app:settings.sign_out')}
        </button>
      </Section>
    </div>
  );
}

function PttControls() {
  const { t } = useTranslation(['app']);
  const [ptt, setPtt] = useState<PttSettings>(() => getPttSettings());
  const [capturing, setCapturing] = useState(false);

  useEffect(() => {
    return subscribePttSettings(setPtt);
  }, []);

  useEffect(() => {
    if (!capturing) return;
    const onKey = (e: KeyboardEvent) => {
      e.preventDefault();
      if (e.code === 'Escape') {
        setCapturing(false);
        return;
      }
      updatePttSettings({ key: e.code, keyLabel: keyCodeToLabel(e.code) });
      setCapturing(false);
    };
    window.addEventListener('keydown', onKey, { capture: true });
    return () => window.removeEventListener('keydown', onKey, { capture: true });
  }, [capturing]);

  return (
    <>
      <Toggle
        label={t('app:settings.ptt_enabled', { defaultValue: 'Push-to-Talk' })}
        hint={t('app:settings.ptt_enabled_hint', {
          defaultValue:
            'Mic bleibt stumm bis die Taste gedrückt wird. Sonst overrides der normale Mute-Button.',
        })}
        checked={ptt.enabled}
        onChange={(v) => updatePttSettings({ enabled: v })}
      />
      <SettingRow
        label={t('app:settings.ptt_key', { defaultValue: 'Hotkey' })}
      >
        <button
          type="button"
          onClick={() => setCapturing((v) => !v)}
          className={
            'inline-flex min-w-[7rem] cursor-pointer items-center justify-center rounded-lg border px-3 py-1.5 text-xs font-mono font-semibold transition focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-400/40 ' +
            (capturing
              ? 'border-brand-400 bg-brand-500/20 text-white animate-pulse'
              : 'border-white/10 bg-ink-800 text-neutral-200 hover:bg-ink-700')
          }
        >
          {capturing
            ? t('app:settings.ptt_press_key', { defaultValue: 'Taste drücken…' })
            : ptt.keyLabel}
        </button>
      </SettingRow>
    </>
  );
}

function CallE2EEControls() {
  const { t } = useTranslation(['app']);
  const [cfg, setCfg] = useState<CallE2EESettings>(() => getCallE2EESettings());
  const [supported] = useState<boolean>(() => isE2EESupported());

  useEffect(() => subscribeCallE2EESettings(setCfg), []);

  return (
    <>
      <Toggle
        label={t('app:settings.e2ee_calls', { defaultValue: 'Ende-zu-Ende-Verschlüsselung (Calls)' })}
        hint={
          supported
            ? t('app:settings.e2ee_calls_hint', {
                defaultValue:
                  'Audio + Video werden vor dem Upload verschlüsselt. Der Server sieht nur Ciphertext. Alle Teilnehmer müssen die Option aktiv haben.',
              })
            : t('app:settings.e2ee_calls_unsupported', {
                defaultValue:
                  'Dein Browser unterstützt keine Insertable Streams. E2EE-Calls nicht verfügbar.',
              })
        }
        checked={cfg.enabled && supported}
        disabled={!supported}
        onChange={(v) => updateCallE2EESettings({ enabled: v })}
      />
    </>
  );
}

function AudioQualityControls() {
  const { t } = useTranslation(['app']);
  const [cfg, setCfg] = useState<AudioSettings>(() => getAudioSettings());

  useEffect(() => subscribeAudioSettings(setCfg), []);

  const params = getAudioQualityParams(cfg.quality);
  const labels: Record<AudioQuality, string> = {
    voice: t('app:settings.audio_voice', { defaultValue: 'Sprache (Empfohlen)' }),
    hifi: t('app:settings.audio_hifi', { defaultValue: 'HiFi / Musik' }),
  };

  return (
    <>
      <SettingRow label={t('app:settings.audio_quality', { defaultValue: 'Audio-Qualität' })}>
        <div className="inline-flex rounded-lg border border-white/10 bg-ink-800 p-1">
          {AUDIO_QUALITY_ORDER.map((q) => {
            const active = cfg.quality === q;
            return (
              <button
                key={q}
                type="button"
                onClick={() => updateAudioSettings({ quality: q })}
                className={
                  'cursor-pointer rounded-md px-3 py-1 text-xs font-medium transition focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-400/40 ' +
                  (active
                    ? 'bg-brand-500/25 text-white ring-1 ring-brand-400/40'
                    : 'text-neutral-400 hover:text-neutral-200')
                }
              >
                {labels[q]}
              </button>
            );
          })}
        </div>
      </SettingRow>
      <div className="rounded-lg border border-white/5 bg-ink-900/40 p-3 text-[11px] text-neutral-400">
        <div className="grid grid-cols-4 gap-3">
          <Stat label="Bitrate" value={params.bitrateKbps + ' kbps'} />
          <Stat label="Channels" value={params.stereo ? 'Stereo' : 'Mono'} />
          <Stat label="Sample" value={params.sampleRateHz / 1000 + ' kHz'} />
          <Stat label="DSP" value={params.echoCancellation ? 'On' : 'Off'} />
        </div>
      </div>
      <p className="text-xs text-neutral-500">
        {cfg.quality === 'hifi'
          ? t('app:settings.audio_hifi_hint', {
              defaultValue:
                'Stereo 510 kbps Opus ohne Noise-Suppression/Echo-Cancellation — bester Musik/Broadcast-Sound. Erfordert ruhige Umgebung.',
            })
          : t('app:settings.audio_voice_hint', {
              defaultValue:
                'Mono 48 kbps mit Noise-Suppression, Echo-Cancellation und Auto-Gain. Optimiert für Sprache im Raum.',
            })}
      </p>
    </>
  );
}

function DeviceKeyBackupControls() {
  const { t } = useTranslation(['app']);
  const { profile, device } = useAuth();
  const [busy, setBusy] = useState(false);
  const [backupOut, setBackupOut] = useState<string | null>(null);
  const [exportPass, setExportPass] = useState('');
  const [importPass, setImportPass] = useState('');
  const [importBlob, setImportBlob] = useState('');
  const [msg, setMsg] = useState<{ kind: 'ok' | 'err'; text: string } | null>(null);

  const canRun = !!profile?.userId && !!device?.id;

  async function handleExport() {
    if (!canRun) return;
    setMsg(null);
    setBusy(true);
    try {
      const priv = await loadDevicePrivateKey(devLocalSecretStore, profile.userId, device.id);
      if (!priv) throw new Error('No device key on this install');
      const out = await exportDeviceKey(priv, exportPass);
      setBackupOut(out);
      setExportPass('');
      setMsg({
        kind: 'ok',
        text: t('app:settings.backup_export_ok', {
          defaultValue: 'Backup erstellt — kopiere und bewahre es sicher auf.',
        }),
      });
    } catch (err: unknown) {
      setMsg({
        kind: 'err',
        text: err instanceof Error ? err.message : 'export failed',
      });
    } finally {
      setBusy(false);
    }
  }

  async function handleImport() {
    if (!canRun) return;
    setMsg(null);
    setBusy(true);
    try {
      const priv = await importDeviceKey(importBlob.trim(), importPass);
      await saveDevicePrivateKey(devLocalSecretStore, profile.userId, device.id, priv);
      setImportBlob('');
      setImportPass('');
      setMsg({
        kind: 'ok',
        text: t('app:settings.backup_import_ok', {
          defaultValue:
            'Schlüssel importiert. Beim nächsten Reload sollten alte Nachrichten lesbar sein.',
        }),
      });
    } catch (err: unknown) {
      setMsg({
        kind: 'err',
        text: err instanceof Error ? err.message : 'import failed',
      });
    } finally {
      setBusy(false);
    }
  }

  return (
    <div className="mt-4 rounded-xl border border-white/10 bg-ink-900/40 p-4">
      <div className="text-sm font-semibold text-white">
        {t('app:settings.device_key_backup', { defaultValue: 'Geräteschlüssel-Backup' })}
      </div>
      <p className="mt-1 text-xs text-neutral-400">
        {t('app:settings.device_key_backup_hint', {
          defaultValue:
            'Sichere deinen privaten Schlüssel passwortgeschützt, damit du auf neuen Geräten alte Nachrichten weiter lesen kannst.',
        })}
      </p>

      <div className="mt-4 space-y-2">
        <div className="text-xs font-semibold uppercase tracking-wide text-neutral-500">
          {t('app:settings.backup_export', { defaultValue: 'Export' })}
        </div>
        <div className="flex gap-2">
          <input
            type="password"
            value={exportPass}
            onChange={(e) => setExportPass(e.target.value)}
            placeholder={t('app:settings.backup_passphrase', { defaultValue: 'Passphrase (min 8)' })}
            className="flex-1 rounded-lg border border-white/10 bg-ink-800 px-3 py-2 text-sm text-white placeholder-neutral-500 focus:border-brand-400 focus:outline-none"
          />
          <button
            type="button"
            disabled={busy || exportPass.length < 8 || !canRun}
            onClick={() => void handleExport()}
            className="cursor-pointer rounded-lg bg-brand-500/80 px-4 text-sm font-semibold text-white transition hover:bg-brand-400 disabled:cursor-not-allowed disabled:opacity-50"
          >
            {t('app:settings.backup_create', { defaultValue: 'Erstellen' })}
          </button>
        </div>
        {backupOut && (
          <textarea
            readOnly
            value={backupOut}
            onClick={(e) => (e.target as HTMLTextAreaElement).select()}
            rows={3}
            className="w-full rounded-lg border border-emerald-500/30 bg-ink-950/60 p-2 font-mono text-[10px] text-emerald-200"
          />
        )}
      </div>

      <div className="mt-4 space-y-2 border-t border-white/5 pt-4">
        <div className="text-xs font-semibold uppercase tracking-wide text-neutral-500">
          {t('app:settings.backup_import', { defaultValue: 'Import' })}
        </div>
        <textarea
          value={importBlob}
          onChange={(e) => setImportBlob(e.target.value)}
          rows={3}
          placeholder={t('app:settings.backup_blob_placeholder', {
            defaultValue: 'chatapp-backup-v1.…',
          })}
          className="w-full rounded-lg border border-white/10 bg-ink-800 p-2 font-mono text-[11px] text-white placeholder-neutral-500 focus:border-brand-400 focus:outline-none"
        />
        <div className="flex gap-2">
          <input
            type="password"
            value={importPass}
            onChange={(e) => setImportPass(e.target.value)}
            placeholder={t('app:settings.backup_passphrase', { defaultValue: 'Passphrase' })}
            className="flex-1 rounded-lg border border-white/10 bg-ink-800 px-3 py-2 text-sm text-white placeholder-neutral-500 focus:border-brand-400 focus:outline-none"
          />
          <button
            type="button"
            disabled={busy || !importBlob || !importPass || !canRun}
            onClick={() => void handleImport()}
            className="cursor-pointer rounded-lg bg-emerald-500/80 px-4 text-sm font-semibold text-white transition hover:bg-emerald-400 disabled:cursor-not-allowed disabled:opacity-50"
          >
            {t('app:settings.backup_restore', { defaultValue: 'Wiederherstellen' })}
          </button>
        </div>
      </div>

      {msg && (
        <p
          className={
            'mt-3 text-xs ' +
            (msg.kind === 'ok' ? 'text-emerald-300' : 'text-rose-300')
          }
        >
          {msg.text}
        </p>
      )}
    </div>
  );
}

function ScreenShareControls() {
  const { t } = useTranslation(['app']);
  const [cfg, setCfg] = useState<ScreenShareSettings>(() => getScreenShareSettings());

  useEffect(() => subscribeScreenShareSettings(setCfg), []);

  const params = getPresetParams(cfg.preset);

  return (
    <>
      <SettingRow label={t('app:settings.screen_share_quality', { defaultValue: 'Qualität' })}>
        <select
          value={cfg.preset}
          onChange={(e) =>
            updateScreenShareSettings({ preset: e.target.value as ScreenSharePreset })
          }
          className="cursor-pointer rounded-lg border border-white/10 bg-ink-800 px-3 py-1.5 text-xs text-neutral-200 focus:border-brand-400 focus:outline-none focus-visible:ring-2 focus-visible:ring-brand-400/40"
        >
          {PRESET_ORDER.map((p) => (
            <option key={p} value={p}>
              {getPresetParams(p).label}
            </option>
          ))}
        </select>
      </SettingRow>
      <div className="rounded-lg border border-white/5 bg-ink-900/40 p-3 text-[11px] text-neutral-400">
        <div className="grid grid-cols-3 gap-3">
          <Stat label="Bitrate (max)" value={formatBitrate(params.bitrateKbps)} />
          <Stat
            label="Resolution"
            value={params.dims ? params.dims.width + '×' + params.dims.height : 'Auto'}
          />
          <Stat label="Framerate" value={params.framerate + ' fps'} />
        </div>
      </div>
      <p className="text-xs text-neutral-500">
        {t('app:settings.screen_share_hint', {
          defaultValue:
            'WebRTC passt Bitrate + Auflösung dynamisch an die Netzwerkqualität an (SVC/VP9). Die Werte sind Obergrenzen. Änderungen greifen beim nächsten Call.',
        })}
      </p>
    </>
  );
}

function Stat({ label, value }: { label: string; value: string }) {
  return (
    <div>
      <div className="text-[10px] uppercase tracking-wide text-neutral-500">{label}</div>
      <div className="mt-0.5 font-mono text-neutral-200">{value}</div>
    </div>
  );
}

function formatBitrate(kbps: number): string {
  if (kbps >= 1000) {
    return (kbps / 1000).toFixed(kbps % 1000 === 0 ? 0 : 1) + ' Mbps';
  }
  return kbps + ' kbps';
}

function Section({ title, children }: { title: string; children: React.ReactNode }) {
  return (
    <section className="rounded-2xl border border-white/10 bg-ink-900/60 p-5 backdrop-blur-xl">
      <h2 className="mb-4 text-xs font-semibold uppercase tracking-wide text-neutral-400">
        {title}
      </h2>
      <div className="space-y-3">{children}</div>
    </section>
  );
}

function Row({ label, value, mono }: { label: string; value: string; mono?: boolean }) {
  return (
    <div className="flex items-center justify-between gap-4">
      <dt className="text-sm text-neutral-500">{label}</dt>
      <dd
        className={
          'max-w-[60%] truncate text-right text-sm text-neutral-200 ' +
          (mono ? 'font-mono text-xs' : '')
        }
        title={value}
      >
        {value}
      </dd>
    </div>
  );
}

function SettingRow({ label, children }: { label: string; children: React.ReactNode }) {
  return (
    <div className="flex items-center justify-between gap-4">
      <span className="text-sm text-neutral-200">{label}</span>
      {children}
    </div>
  );
}

function Toggle({
  label,
  hint,
  checked,
  disabled,
  onChange,
}: {
  label: string;
  hint?: string;
  checked: boolean;
  disabled?: boolean;
  onChange: (next: boolean) => void;
}) {
  return (
    <label className="flex cursor-pointer items-start justify-between gap-4">
      <span className="min-w-0 flex-1">
        <span className="block text-sm text-neutral-200">{label}</span>
        {hint && <span className="mt-1 block text-xs text-neutral-500">{hint}</span>}
      </span>
      <span className="relative mt-0.5 inline-flex h-6 w-11 shrink-0">
        <input
          type="checkbox"
          checked={checked}
          disabled={disabled}
          onChange={(e) => onChange(e.target.checked)}
          className="peer sr-only"
        />
        <span className="inline-block h-6 w-11 rounded-full bg-neutral-700 transition peer-checked:bg-brand-500/70 peer-disabled:opacity-50" />
        <span className="absolute left-0.5 top-0.5 h-5 w-5 rounded-full bg-white transition peer-checked:translate-x-5" />
      </span>
    </label>
  );
}
