'use client';
// Settings.tsx — 设置：偏好(语言/主题) + 设备管理(列表/移除/二次确认) + TOTP 2FA(绑定/验证/解禁)。
// 设计稿 §5：Web 用户中心「设置(含 2FA/TOTP 开关,用户可自选开启)」。
import React, { useEffect, useState } from 'react';
import { Icon } from './icons';
import { card, input } from './shared';
import { ErrorLine } from './Login';
import { useUI } from '../lib/theme';
import type { TFn, Lang } from '../lib/i18n';
import { getClient } from '../lib/api/client';
import { bilingual } from '../lib/api/errors';
import type { Device, TotpSetup } from '../lib/api/types';

export default function Settings({ t, lang, totpEnabled, onTotpChange }: { t: TFn; lang: Lang; totpEnabled: boolean; onTotpChange: () => void }) {
  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 18 }}>
      <div style={{ fontFamily: 'var(--font-display)', fontSize: 25, fontWeight: 700, color: 'var(--fg1)' }}>{t('settingsTitle')}</div>
      <Preferences t={t} />
      <TotpSection t={t} lang={lang} enabled={totpEnabled} onChange={onTotpChange} />
      <Devices t={t} lang={lang} />
    </div>
  );
}

const sectionTitle: React.CSSProperties = { fontSize: 14.5, fontWeight: 700, color: 'var(--fg1)' };

function Preferences({ t }: { t: TFn }) {
  const { lang, setLang, theme, setTheme } = useUI();
  return (
    <div style={{ ...card, padding: '18px 20px', display: 'flex', flexDirection: 'column', gap: 16 }}>
      <div style={sectionTitle}>{t('prefTitle')}</div>
      <Row label={t('prefLang')}>
        <Seg
          value={lang}
          options={[['zh', '中文'], ['en', 'EN']]}
          onPick={(v) => setLang(v as Lang)}
        />
      </Row>
      <Row label={t('prefTheme')}>
        <Seg
          value={theme}
          options={[['light', t('themeLight')], ['dark', t('themeDark')]]}
          icons={{ light: 'sun', dark: 'moon' }}
          onPick={(v) => setTheme(v as 'light' | 'dark')}
        />
      </Row>
    </div>
  );
}

function Row({ label, children }: { label: string; children: React.ReactNode }) {
  return (
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12 }}>
      <span style={{ fontSize: 13.5, fontWeight: 600, color: 'var(--fg2)' }}>{label}</span>
      {children}
    </div>
  );
}

function Seg({ value, options, onPick, icons }: { value: string; options: [string, string][]; onPick: (v: string) => void; icons?: Record<string, string> }) {
  return (
    <div style={{ display: 'flex', background: 'var(--bg-subtle)', borderRadius: 999, padding: 3, gap: 2 }}>
      {options.map(([v, l]) => (
        <button
          key={v}
          onClick={() => onPick(v)}
          aria-pressed={value === v}
          style={{ display: 'inline-flex', alignItems: 'center', gap: 6, border: 'none', cursor: 'pointer', borderRadius: 999, padding: '6px 14px', fontFamily: 'var(--font-sans)', fontSize: 12.5, fontWeight: 700, background: value === v ? 'var(--accent)' : 'transparent', color: value === v ? 'var(--fg-on-accent)' : 'var(--fg3)' }}
        >
          {icons && <Icon name={icons[v]} size={14} color={value === v ? 'var(--fg-on-accent)' : 'var(--fg3)'} />}
          {l}
        </button>
      ))}
    </div>
  );
}

/* ───────── TOTP 2FA ───────── */
function TotpSection({ t, lang, enabled, onChange }: { t: TFn; lang: Lang; enabled: boolean; onChange: () => void }) {
  const api = getClient();
  const [mode, setMode] = useState<'idle' | 'setup' | 'disable'>('idle');
  const [setup, setSetup] = useState<TotpSetup | null>(null);
  const [code, setCode] = useState('');
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState('');
  const [flash, setFlash] = useState('');

  function reset() {
    setMode('idle');
    setCode('');
    setErr('');
    setSetup(null);
  }

  async function startSetup() {
    setBusy(true);
    setErr('');
    try {
      const s = await api.totpSetup();
      setSetup(s);
      setMode('setup');
    } catch (e) {
      setErr(bilingual(e, lang));
    } finally {
      setBusy(false);
    }
  }

  async function verify() {
    if (code.length !== 6 || busy) return;
    setBusy(true);
    setErr('');
    try {
      await api.totpVerify(code);
      reset();
      setFlash(t('totpEnabledOk'));
      onChange();
    } catch (e) {
      setErr(bilingual(e, lang));
    } finally {
      setBusy(false);
    }
  }

  async function disable() {
    if (code.length !== 6 || busy) return;
    setBusy(true);
    setErr('');
    try {
      await api.totpDisable(code);
      reset();
      setFlash(t('totpDisabledOk'));
      onChange();
    } catch (e) {
      setErr(bilingual(e, lang));
    } finally {
      setBusy(false);
    }
  }

  return (
    <div style={{ ...card, padding: '18px 20px', display: 'flex', flexDirection: 'column', gap: 14 }}>
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12, flexWrap: 'wrap' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <div style={{ width: 38, height: 38, borderRadius: 'var(--radius-md)', background: 'var(--accent-subtle)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <Icon name="shield-check" size={19} color="var(--accent)" />
          </div>
          <div>
            <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
              <span style={sectionTitle}>{t('totpTitle')}</span>
              <span style={{ fontSize: 10.5, fontWeight: 700, padding: '2px 9px', borderRadius: 999, background: enabled ? 'var(--success-subtle)' : 'var(--bg-subtle)', color: enabled ? 'var(--success)' : 'var(--fg3)' }}>
                {enabled ? t('totpOn') : t('totpOff')}
              </span>
            </div>
            <div style={{ fontSize: 12, color: 'var(--fg3)', marginTop: 4, lineHeight: 1.5, maxWidth: 380 }}>{t('totpDesc')}</div>
          </div>
        </div>
        {mode === 'idle' && (
          enabled ? (
            <button onClick={() => { setMode('disable'); setFlash(''); }} style={ghostBtn}>{t('totpDisableBtn')}</button>
          ) : (
            <button onClick={startSetup} disabled={busy} style={accentBtn}>{busy ? t('loading') : t('totpEnable')}</button>
          )
        )}
      </div>

      {flash && (
        <div style={{ display: 'flex', alignItems: 'center', gap: 7, color: 'var(--success)', fontSize: 12.5, fontWeight: 600 }}>
          <Icon name="check-circle" size={14} color="var(--success)" />{flash}
        </div>
      )}

      {mode === 'setup' && setup && (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 14, borderTop: '1px solid var(--border)', paddingTop: 14 }}>
          <div style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--fg2)' }}>{t('totpStep1')}</div>
          <div style={{ display: 'flex', gap: 16, flexWrap: 'wrap', alignItems: 'center' }}>
            <QrPlaceholder uri={setup.otpauthUri} />
            <div style={{ minWidth: 200 }}>
              <div style={{ fontSize: 11.5, color: 'var(--fg3)', fontWeight: 600, marginBottom: 6 }}>{t('totpSecretLabel')}</div>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8, background: 'var(--bg-subtle)', border: '1px solid var(--border)', borderRadius: 'var(--radius-md)', padding: '10px 12px' }}>
                <span style={{ fontFamily: 'var(--font-mono)', fontSize: 14, letterSpacing: '0.12em', color: 'var(--fg1)', wordBreak: 'break-all' }}>{setup.secret}</span>
                <button onClick={() => navigator.clipboard?.writeText(setup.secret).catch(() => {})} title={t('copyKey')} style={{ border: 'none', background: 'transparent', cursor: 'pointer', padding: 2, display: 'flex' }}>
                  <Icon name="copy" size={15} color="var(--accent)" />
                </button>
              </div>
            </div>
          </div>
          <div style={{ fontSize: 12.5, fontWeight: 600, color: 'var(--fg2)', marginTop: 2 }}>{t('totpStep2')}</div>
          <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>
            <input
              value={code}
              onChange={(e) => { setCode(e.target.value.replace(/\D/g, '').slice(0, 6)); setErr(''); }}
              onKeyDown={(e) => e.key === 'Enter' && verify()}
              placeholder="······"
              style={{ ...input, width: 160, fontFamily: 'var(--font-mono)', fontSize: 18, letterSpacing: '0.4em', textAlign: 'center' }}
            />
            <button onClick={verify} disabled={code.length !== 6 || busy} style={{ ...accentBtn, opacity: code.length === 6 && !busy ? 1 : 0.5 }}>{t('totpVerifyBtn')}</button>
            <button onClick={reset} style={ghostBtn}>{t('cancel')}</button>
          </div>
          {err && <ErrorLine text={err} />}
        </div>
      )}

      {mode === 'disable' && (
        <div style={{ display: 'flex', flexDirection: 'column', gap: 12, borderTop: '1px solid var(--border)', paddingTop: 14 }}>
          <div style={{ fontSize: 12.5, color: 'var(--fg2)' }}>{t('totpDisableHint')}</div>
          <div style={{ display: 'flex', gap: 10, flexWrap: 'wrap' }}>
            <input
              value={code}
              onChange={(e) => { setCode(e.target.value.replace(/\D/g, '').slice(0, 6)); setErr(''); }}
              onKeyDown={(e) => e.key === 'Enter' && disable()}
              placeholder="······"
              style={{ ...input, width: 160, fontFamily: 'var(--font-mono)', fontSize: 18, letterSpacing: '0.4em', textAlign: 'center' }}
            />
            <button onClick={disable} disabled={code.length !== 6 || busy} style={{ ...dangerBtn, opacity: code.length === 6 && !busy ? 1 : 0.5 }}>{t('totpDisableBtn')}</button>
            <button onClick={reset} style={ghostBtn}>{t('cancel')}</button>
          </div>
          {err && <ErrorLine text={err} />}
        </div>
      )}
    </div>
  );
}

// 二维码占位：与订阅页一致的设计语言(dashed 框 + qr 图标)。mock 阶段不引入 QR 依赖。
function QrPlaceholder({ uri }: { uri: string }) {
  return (
    <div title={uri} style={{ width: 128, height: 128, borderRadius: 'var(--radius-md)', background: 'var(--bg-subtle)', border: '1px dashed var(--border-strong)', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 6, flexShrink: 0 }}>
      <Icon name="qr-code" size={40} color="var(--fg3)" stroke={1.5} />
      <span style={{ fontSize: 10, color: 'var(--fg3)', fontWeight: 600 }}>otpauth://</span>
    </div>
  );
}

/* ───────── Devices ───────── */
function Devices({ t, lang }: { t: TFn; lang: Lang }) {
  const api = getClient();
  const [devices, setDevices] = useState<Device[] | null>(null);
  const [confirmId, setConfirmId] = useState<string | null>(null);
  const [busy, setBusy] = useState(false);
  const [err, setErr] = useState('');

  async function load() {
    try {
      setDevices(await api.listDevices());
    } catch (e) {
      setErr(bilingual(e, lang));
    }
  }
  // 仅挂载时拉取一次设备列表
  // eslint-disable-next-line react-hooks/exhaustive-deps
  useEffect(() => { load(); }, []);

  async function remove(id: string) {
    setBusy(true);
    setErr('');
    try {
      await api.removeDevice(id);
      setConfirmId(null);
      await load();
    } catch (e) {
      setErr(bilingual(e, lang));
    } finally {
      setBusy(false);
    }
  }

  return (
    <div style={{ ...card, overflow: 'hidden' }}>
      <div style={{ padding: '16px 20px 12px' }}>
        <div style={sectionTitle}>{t('devTitle')}</div>
        <div style={{ fontSize: 12, color: 'var(--fg3)', marginTop: 4, lineHeight: 1.5 }}>{t('devSub')}</div>
      </div>
      {err && <div style={{ padding: '0 20px 12px' }}><ErrorLine text={err} /></div>}
      {devices === null ? (
        <div style={{ padding: '8px 20px 18px', fontSize: 13, color: 'var(--fg3)' }}>{t('loading')}</div>
      ) : devices.length === 0 ? (
        <div style={{ padding: '8px 20px 18px', fontSize: 13, color: 'var(--fg3)' }}>{t('devEmpty')}</div>
      ) : (
        devices.map((d, i) => (
          <div key={d.id} style={{ display: 'flex', alignItems: 'center', gap: 12, padding: '13px 20px', borderTop: '1px solid var(--border)' }}>
            <div style={{ width: 34, height: 34, borderRadius: 'var(--radius-md)', background: 'var(--bg-subtle)', display: 'flex', alignItems: 'center', justifyContent: 'center', flexShrink: 0 }}>
              <Icon name={/i(Pad|Phone)|Android|iOS/i.test(d.platform) ? 'smartphone' : 'monitor'} size={17} color="var(--accent)" />
            </div>
            <div style={{ flex: 1, minWidth: 0 }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                <span style={{ fontSize: 13.5, fontWeight: 600, color: 'var(--fg1)' }}>{d.name}</span>
                {d.current && <span style={{ fontSize: 10, fontWeight: 700, padding: '2px 8px', borderRadius: 999, background: 'var(--accent-subtle)', color: 'var(--accent)' }}>{t('devCurrent')}</span>}
              </div>
              <div style={{ fontSize: 11.5, color: 'var(--fg3)', marginTop: 2 }}>{d.platform} · {t('devLastActive')} {d.lastActive}</div>
            </div>
            {!d.current && (
              <button onClick={() => setConfirmId(d.id)} style={{ display: 'inline-flex', alignItems: 'center', gap: 6, border: '1.5px solid var(--border-strong)', background: 'transparent', color: 'var(--danger)', fontWeight: 600, fontSize: 12.5, padding: '7px 13px', borderRadius: 'var(--radius-full)', cursor: 'pointer' }}>
                <Icon name="trash-2" size={14} color="var(--danger)" />{t('devRemove')}
              </button>
            )}
          </div>
        ))
      )}

      {confirmId && (
        <ConfirmModal
          t={t}
          busy={busy}
          onCancel={() => setConfirmId(null)}
          onConfirm={() => remove(confirmId)}
        />
      )}
    </div>
  );
}

function ConfirmModal({ t, busy, onCancel, onConfirm }: { t: TFn; busy: boolean; onCancel: () => void; onConfirm: () => void }) {
  return (
    <div onClick={onCancel} style={{ position: 'fixed', inset: 0, zIndex: 50, background: 'var(--overlay)', display: 'flex', alignItems: 'center', justifyContent: 'center', padding: 20 }}>
      <div onClick={(e) => e.stopPropagation()} style={{ ...card, width: 380, maxWidth: '100%', padding: '24px 24px 20px' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 10 }}>
          <div style={{ width: 38, height: 38, borderRadius: 'var(--radius-md)', background: 'var(--danger-subtle)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
            <Icon name="alert-triangle" size={19} color="var(--danger)" />
          </div>
          <span style={{ fontFamily: 'var(--font-display)', fontWeight: 700, fontSize: 17, color: 'var(--fg1)' }}>{t('devRemoveConfirmTitle')}</span>
        </div>
        <div style={{ fontSize: 13, color: 'var(--fg3)', lineHeight: 1.6, marginBottom: 18 }}>{t('devRemoveConfirmSub')}</div>
        <div style={{ display: 'flex', gap: 10, justifyContent: 'flex-end' }}>
          <button onClick={onCancel} style={ghostBtn}>{t('cancel')}</button>
          <button onClick={onConfirm} disabled={busy} style={dangerBtn}>{busy ? t('loading') : t('confirm')}</button>
        </div>
      </div>
    </div>
  );
}

const accentBtn: React.CSSProperties = { border: 'none', borderRadius: 'var(--radius-full)', padding: '9px 18px', background: 'var(--accent)', color: 'var(--fg-on-accent)', fontWeight: 700, fontSize: 13, cursor: 'pointer' };
const ghostBtn: React.CSSProperties = { border: '1.5px solid var(--border-strong)', borderRadius: 'var(--radius-full)', padding: '9px 18px', background: 'transparent', color: 'var(--fg2)', fontWeight: 600, fontSize: 13, cursor: 'pointer' };
const dangerBtn: React.CSSProperties = { border: 'none', borderRadius: 'var(--radius-full)', padding: '9px 18px', background: 'var(--danger)', color: '#fff', fontWeight: 700, fontSize: 13, cursor: 'pointer' };
