/*
 *  SettingsModal.tsx
 *  Zyquo Cloud Web
 *
 *  Author: Simon-Pierre Boucher
 *  Mail: contact@spboucher.ai
 *
 *  Settings: Providers & Keys (masked fields, Test with status dot + latency,
 *  proxy base URL, honesty notice), Models (catalog browser, favorites,
 *  default), Appearance (light default / dark / system, accents, font size),
 *  Data (export/import/clear), Advanced (passphrase lock, default system
 *  prompt, streaming toggle).
 */

import { useMemo, useRef, useState } from 'react'
import { ACCENT_SWATCHES } from '../design/accents'
import { CATALOG, priceBadge } from '../features/catalogHelpers'
import { downloadBackup } from '../features/exporters'
import { testKey } from '../providers/testKey'
import { PROVIDER_META } from '../providers/registry'
import { useStore } from '../state/store'
import { importAll, isExportedData, clearEverything } from '../storage/backup'
import { clearConversations } from '../storage/conversations'
import { getKey, maskedKey, removeKey, setKey } from '../storage/keys'
import { disableVault, enableVault, isVaultEnabled, persistVault } from '../storage/vault'
import { contextBadge, BUILT_IN_PROVIDERS, type Provider } from '../types'
import {
  IconBrain,
  IconEye,
  IconStar,
  IconWrench,
  IconX,
  ProviderGlyph,
} from './icons'

const TABS = [
  { id: 'providers', label: 'Providers & Keys' },
  { id: 'models', label: 'Models' },
  { id: 'appearance', label: 'Appearance' },
  { id: 'data', label: 'Data' },
  { id: 'advanced', label: 'Advanced' },
]

type TestState = { status: 'idle' | 'testing' | 'ok' | 'fail'; detail?: string }

export default function SettingsModal() {
  const settingsTab = useStore((s) => s.settingsTab)
  const closeSettings = useStore((s) => s.closeSettings)
  const [tab, setTab] = useState(settingsTab)

  return (
    <div className="overlay" onMouseDown={(e) => e.target === e.currentTarget && closeSettings()}>
      <div className="panel settings-panel" role="dialog" aria-label="Settings">
        <div className="panel-search" style={{ justifyContent: 'space-between' }}>
          <strong style={{ fontSize: 14 }}>Settings</strong>
          <button className="icon-button" onClick={closeSettings}>
            <IconX />
          </button>
        </div>
        <div className="settings-body">
          <nav className="settings-tabs">
            {TABS.map((t) => (
              <button
                key={t.id}
                className={`settings-tab${tab === t.id ? ' active' : ''}`}
                onClick={() => setTab(t.id)}
              >
                {t.label}
              </button>
            ))}
          </nav>
          <div className="settings-content">
            {tab === 'providers' && <ProvidersTab />}
            {tab === 'models' && <ModelsTab />}
            {tab === 'appearance' && <AppearanceTab />}
            {tab === 'data' && <DataTab />}
            {tab === 'advanced' && <AdvancedTab />}
          </div>
        </div>
      </div>
    </div>
  )
}

function ProvidersTab() {
  const refreshKeyedProviders = useStore((s) => s.refreshKeyedProviders)
  const settings = useStore((s) => s.settings)
  const updateSettings = useStore((s) => s.updateSettings)
  const [drafts, setDrafts] = useState<Partial<Record<Provider, string>>>({})
  const [tests, setTests] = useState<Partial<Record<Provider, TestState>>>({})
  const [proxyFor, setProxyFor] = useState<Provider | null>(null)
  const [, forceRender] = useState(0)

  const saveDraft = (provider: Provider) => {
    const draft = drafts[provider]
    if (draft !== undefined && draft !== '') {
      setKey(provider, draft.trim())
      setDrafts((d) => ({ ...d, [provider]: undefined }))
      refreshKeyedProviders()
      forceRender((n) => n + 1)
    }
  }

  const runTest = async (provider: Provider) => {
    saveDraft(provider)
    const key = getKey(provider)
    if (!key) {
      setTests((t) => ({ ...t, [provider]: { status: 'fail', detail: 'No key' } }))
      return
    }
    setTests((t) => ({ ...t, [provider]: { status: 'testing' } }))
    try {
      const ms = await testKey(provider, key, settings.proxyBaseURLs[provider])
      setTests((t) => ({
        ...t,
        [provider]: { status: 'ok', detail: `Verified · ${Math.round(ms)} ms` },
      }))
    } catch (err) {
      setTests((t) => ({
        ...t,
        [provider]: { status: 'fail', detail: err instanceof Error ? err.message : String(err) },
      }))
    }
  }

  return (
    <div>
      <div className="first-run-note" style={{ marginBottom: 16 }}>
        <span>
          <strong>Your keys stay in this browser.</strong> They're stored in localStorage on this
          device and sent only to the provider you call. Anyone with access to this browser
          profile (or any script that runs on this page) could read them — that's inherent to a
          backend-less app. Use the optional passphrase lock in Advanced for at-rest encryption.
        </span>
      </div>
      {BUILT_IN_PROVIDERS.map((provider) => {
        const saved = getKey(provider)
        const test = tests[provider] ?? { status: 'idle' }
        const proxy = settings.proxyBaseURLs[provider]
        return (
          <div className="settings-row" key={provider}>
            <span className="provider-name">
              <span style={{ color: 'var(--z-accent)', display: 'inline-flex' }}>
                <ProviderGlyph provider={provider} size={13} />
              </span>
              {PROVIDER_META[provider].displayName}
              <span
                className={`status-dot ${
                  test.status === 'ok'
                    ? 'ok'
                    : test.status === 'fail'
                      ? 'fail'
                      : saved
                        ? 'saved'
                        : ''
                }`}
              />
            </span>
            <input
              className="key-input"
              type="password"
              placeholder={saved ? maskedKey(saved) : 'API key'}
              value={drafts[provider] ?? ''}
              onChange={(e) => setDrafts((d) => ({ ...d, [provider]: e.target.value }))}
              onBlur={() => saveDraft(provider)}
            />
            <button className="button" onClick={() => void runTest(provider)}>
              {test.status === 'testing' ? 'Testing…' : 'Test'}
            </button>
            <button
              className="button"
              title="Proxy / base URL override"
              onClick={() => setProxyFor(proxyFor === provider ? null : provider)}
            >
              Proxy{proxy ? ' •' : ''}
            </button>
            {saved && (
              <button
                className="icon-button danger"
                title="Remove key"
                onClick={() => {
                  removeKey(provider)
                  refreshKeyedProviders()
                  setTests((t) => ({ ...t, [provider]: { status: 'idle' } }))
                  forceRender((n) => n + 1)
                }}
              >
                <IconX size={10} />
              </button>
            )}
            {test.detail && (
              <span className={`settings-sub ${test.status === 'ok' ? 'ok' : 'fail'}`}>
                {test.detail}
              </span>
            )}
            {proxyFor === provider && (
              <div style={{ width: '100%', display: 'flex', gap: 8, alignItems: 'center' }}>
                <input
                  className="text-input"
                  style={{ flex: 1 }}
                  placeholder={`Proxy base URL (e.g. http://localhost:8787) — default: ${PROVIDER_META[provider].defaultBaseURL}`}
                  value={proxy ?? ''}
                  onChange={(e) =>
                    updateSettings({
                      proxyBaseURLs: {
                        ...settings.proxyBaseURLs,
                        [provider]: e.target.value === '' ? undefined : e.target.value,
                      },
                    })
                  }
                />
              </div>
            )}
          </div>
        )
      })}
      <p className="settings-note" style={{ marginTop: 12 }}>
        All 12 providers currently allow direct browser calls (verified — see docs/CORS-MATRIX.md).
        If a provider starts blocking CORS, set a proxy URL above or run Zyquo Router locally and
        point the override at it.
      </p>
    </div>
  )
}

function ModelsTab() {
  const settings = useStore((s) => s.settings)
  const updateSettings = useStore((s) => s.updateSettings)
  const [provider, setProvider] = useState<Provider>('openai')
  const favoriteSet = useMemo(() => new Set(settings.favoriteModelIDs), [settings.favoriteModelIDs])
  const models = useMemo(() => CATALOG.filter((m) => m.provider === provider), [provider])

  return (
    <div>
      <div className="settings-row" style={{ borderBottom: 'none' }}>
        <select
          className="select"
          value={provider}
          onChange={(e) => setProvider(e.target.value as Provider)}
        >
          {BUILT_IN_PROVIDERS.map((p) => (
            <option key={p} value={p}>
              {PROVIDER_META[p].displayName}
            </option>
          ))}
        </select>
        <span className="settings-note">{models.length} models</span>
      </div>
      {models.map((model) => (
        <div className="settings-row" key={model.id}>
          <button
            className={`star${favoriteSet.has(model.id) ? ' active' : ''}`}
            style={{ color: favoriteSet.has(model.id) ? 'var(--z-warning)' : 'var(--z-text-tertiary)' }}
            onClick={() =>
              updateSettings({
                favoriteModelIDs: favoriteSet.has(model.id)
                  ? settings.favoriteModelIDs.filter((id) => id !== model.id)
                  : [...settings.favoriteModelIDs, model.id],
              })
            }
          >
            <IconStar filled={favoriteSet.has(model.id)} />
          </button>
          <div style={{ minWidth: 0, flex: 1 }}>
            <div style={{ fontSize: 13, display: 'flex', gap: 6, alignItems: 'center' }}>
              {model.displayName}
              {model.isRecommended && <span className="badge accent">Featured</span>}
              {model.isLegacy && <span className="badge">Legacy</span>}
              {settings.defaultModelID === model.id && settings.defaultProvider === provider && (
                <span className="badge accent">Default</span>
              )}
            </div>
            <div
              style={{
                fontSize: 10,
                fontFamily: 'var(--z-font-mono)',
                color: 'var(--z-text-tertiary)',
                overflow: 'hidden',
                textOverflow: 'ellipsis',
                whiteSpace: 'nowrap',
              }}
            >
              {model.id}
            </div>
          </div>
          <span className="model-row-badges">
            {model.capabilities.vision && <IconEye />}
            {model.capabilities.reasoning && <IconBrain />}
            {model.capabilities.tools && <IconWrench />}
            <span>{contextBadge(model)}</span>
            <span>{priceBadge(model)}</span>
          </span>
          <button
            className="button"
            onClick={() => updateSettings({ defaultModelID: model.id, defaultProvider: provider })}
          >
            Set default
          </button>
        </div>
      ))}
    </div>
  )
}

function AppearanceTab() {
  const settings = useStore((s) => s.settings)
  const updateSettings = useStore((s) => s.updateSettings)
  return (
    <div>
      <div className="settings-section">
        <h3>Theme</h3>
        <div style={{ display: 'flex', gap: 8 }}>
          {(['light', 'dark', 'system'] as const).map((theme) => (
            <button
              key={theme}
              className={`button${settings.theme === theme ? ' primary' : ''}`}
              onClick={() => updateSettings({ theme })}
            >
              {theme[0]?.toUpperCase() + theme.slice(1)}
            </button>
          ))}
        </div>
        <p className="settings-note" style={{ marginTop: 6 }}>
          Light is the Zyquo flagship theme and the default.
        </p>
      </div>
      <div className="settings-section">
        <h3>Accent</h3>
        <div style={{ display: 'flex', gap: 8 }}>
          {ACCENT_SWATCHES.map(({ id, swatch }) => (
            <button
              key={id}
              title={id}
              onClick={() => updateSettings({ accent: id })}
              style={{
                width: 28,
                height: 28,
                borderRadius: '50%',
                background: swatch,
                border:
                  settings.accent === id
                    ? '2px solid var(--z-text-primary)'
                    : '2px solid transparent',
              }}
            />
          ))}
        </div>
      </div>
      <div className="settings-section">
        <h3>Chat font size</h3>
        <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
          <input
            type="range"
            min={12}
            max={18}
            step={0.5}
            value={settings.chatFontSize}
            style={{ flex: 1, accentColor: 'var(--z-accent)' }}
            onChange={(e) => updateSettings({ chatFontSize: Number(e.target.value) })}
          />
          <span style={{ fontSize: 12 }}>{settings.chatFontSize.toFixed(1)} px</span>
        </div>
        <div
          style={{
            marginTop: 8,
            padding: 12,
            background: 'var(--z-surface)',
            border: 'var(--z-hairline) solid var(--z-border)',
            borderRadius: 10,
            fontSize: settings.chatFontSize,
            lineHeight: 1.45,
          }}
        >
          The quick brown fox jumps over the lazy dog.
        </div>
      </div>
      <div className="settings-section">
        <h3>Density</h3>
        <div style={{ display: 'flex', gap: 8 }}>
          {(['comfortable', 'compact'] as const).map((density) => (
            <button
              key={density}
              className={`button${settings.density === density ? ' primary' : ''}`}
              onClick={() => updateSettings({ density })}
            >
              {density[0]?.toUpperCase() + density.slice(1)}
            </button>
          ))}
        </div>
      </div>
    </div>
  )
}

function DataTab() {
  const toast = useStore((s) => s.toast)
  const loadAll = useStore((s) => s.loadAll)
  const fileRef = useRef<HTMLInputElement>(null)
  const [includeKeys, setIncludeKeys] = useState(false)
  const [confirmClear, setConfirmClear] = useState<string | null>(null)

  const doImport = async (file: File) => {
    try {
      const parsed: unknown = JSON.parse(await file.text())
      if (!isExportedData(parsed)) throw new Error('Not a Zyquo Cloud Web export file')
      const result = await importAll(parsed)
      await loadAll()
      toast(
        `Imported ${result.conversations} conversations${result.keys > 0 ? ` and ${result.keys} keys` : ''}`,
        'success'
      )
    } catch (err) {
      toast(err instanceof Error ? err.message : 'Import failed', 'error')
    }
  }

  return (
    <div>
      <div className="settings-section">
        <h3>Export</h3>
        <label style={{ display: 'flex', gap: 6, alignItems: 'center', fontSize: 12.5 }}>
          <input
            type="checkbox"
            checked={includeKeys}
            onChange={(e) => setIncludeKeys(e.target.checked)}
          />
          Include API keys
        </label>
        {includeKeys && (
          <p className="settings-note" style={{ color: 'var(--z-warning)' }}>
            ⚠ The exported file will contain your API keys in plain text. Store it safely.
          </p>
        )}
        <button
          className="button primary"
          style={{ marginTop: 8 }}
          onClick={() => void downloadBackup(includeKeys)}
        >
          Download backup (JSON)
        </button>
      </div>
      <div className="settings-section">
        <h3>Import</h3>
        <input
          ref={fileRef}
          type="file"
          accept="application/json"
          hidden
          onChange={(e) => {
            const file = e.target.files?.[0]
            if (file) void doImport(file)
            e.target.value = ''
          }}
        />
        <button className="button" onClick={() => fileRef.current?.click()}>
          Import backup file…
        </button>
      </div>
      <div className="settings-section">
        <h3>Clear data</h3>
        <div style={{ display: 'flex', gap: 8, flexWrap: 'wrap' }}>
          {(
            [
              ['conversations', 'Delete all conversations'],
              ['everything', 'Delete everything (keys, history, settings)'],
            ] as const
          ).map(([kind, label]) => (
            <button
              key={kind}
              className="button danger"
              onClick={async () => {
                if (confirmClear !== kind) {
                  setConfirmClear(kind)
                  setTimeout(() => setConfirmClear(null), 4000)
                  return
                }
                if (kind === 'conversations') await clearConversations()
                else await clearEverything()
                await loadAll()
                setConfirmClear(null)
                toast('Cleared', 'success')
                if (kind === 'everything') window.location.reload()
              }}
            >
              {confirmClear === kind ? 'Click again to confirm' : label}
            </button>
          ))}
        </div>
      </div>
    </div>
  )
}

function AdvancedTab() {
  const settings = useStore((s) => s.settings)
  const updateSettings = useStore((s) => s.updateSettings)
  const toast = useStore((s) => s.toast)
  const [passphrase, setPassphrase] = useState('')
  const vaulted = isVaultEnabled()

  return (
    <div>
      <div className="settings-section">
        <h3>Default system prompt</h3>
        <textarea
          className="text-input"
          rows={4}
          placeholder="Applied to new conversations"
          value={settings.defaultSystemPrompt}
          onChange={(e) => updateSettings({ defaultSystemPrompt: e.target.value })}
        />
      </div>
      <div className="settings-section">
        <h3>Passphrase lock</h3>
        <p className="settings-note">
          Encrypts your stored keys with AES-GCM (key derived from your passphrase). Honest
          caveat: once unlocked, a compromised page can still read keys — this protects the data
          at rest, not a running session. Without a passphrase, keys are stored in plaintext.
        </p>
        <div style={{ display: 'flex', gap: 8, marginTop: 8, flexWrap: 'wrap' }}>
          <input
            className="text-input"
            type="password"
            placeholder="Passphrase"
            value={passphrase}
            onChange={(e) => setPassphrase(e.target.value)}
          />
          {!vaulted ? (
            <button
              className="button primary"
              disabled={passphrase.length < 4}
              onClick={async () => {
                await enableVault(passphrase)
                setPassphrase('')
                toast('Passphrase lock enabled', 'success')
              }}
            >
              Enable lock
            </button>
          ) : (
            <>
              <button
                className="button"
                disabled={passphrase.length < 4}
                onClick={async () => {
                  try {
                    await persistVault(passphrase)
                    toast('Vault re-encrypted', 'success')
                  } catch {
                    toast('Wrong passphrase', 'error')
                  }
                }}
              >
                Re-encrypt
              </button>
              <button
                className="button danger"
                disabled={passphrase.length < 4}
                onClick={async () => {
                  try {
                    await disableVault(passphrase)
                    setPassphrase('')
                    toast('Passphrase lock disabled', 'success')
                  } catch {
                    toast('Wrong passphrase', 'error')
                  }
                }}
              >
                Disable lock
              </button>
            </>
          )}
        </div>
        {vaulted && <p className="settings-note" style={{ marginTop: 6 }}>Lock is enabled.</p>}
      </div>
      <div className="settings-section">
        <h3>Streaming</h3>
        <label style={{ display: 'flex', gap: 6, alignItems: 'center', fontSize: 12.5 }}>
          <input
            type="checkbox"
            checked={settings.streamingEnabled}
            onChange={(e) => updateSettings({ streamingEnabled: e.target.checked })}
          />
          Stream responses token-by-token
        </label>
      </div>
    </div>
  )
}
