// AI 플랫폼(LLM Provider) 설정(ADMIN) — 제공자·모델 선택 + 연결 테스트.
//   API 키 값은 화면에 절대 표시/입력하지 않는다(claudeKeySet 으로 설정 여부 배지만).
//   저장은 provider/claudeModel 만 전송(ollama 계열 모델·전역 활성은 읽기 전용 표시).
//   레퍼런스: guardia-ocr AiPlatformSettings.tsx (esn 다크 콘솔 스타일로 미러, glm 추가).
import { useEffect, useState } from 'react'
import { Cpu, KeyRound, PlugZap, Save } from 'lucide-react'
import { getAiConfig, updateAiConfig, testAiConfig } from '../api/adminAiConfig'
import type { AiProvider, ClaudeModel, AiTestResult } from '../api/adminAiConfig'

const PROVIDERS: { id: AiProvider; label: string; hint: string; ram?: boolean }[] = [
  { id: 'ollama', label: 'Ollama (기본)', hint: '온프레미스 · llama3.2:1b' },
  { id: 'qwen3', label: 'Qwen3', hint: '온프레미스 · qwen3:1.7b' },
  { id: 'deepseek', label: 'DeepSeek', hint: '온프레미스 · deepseek-r1:1.5b' },
  { id: 'glm', label: 'GLM', hint: '온프레미스 · glm4:9b', ram: true },
  { id: 'claude', label: 'Claude (외부)', hint: 'api.anthropic.com · 키 필요' },
]

const CLAUDE_MODELS: ClaudeModel[] = ['claude-sonnet-4-6', 'claude-haiku-4-5', 'claude-opus-4-8']
const DEFAULT_CLAUDE_MODEL: ClaudeModel = 'claude-sonnet-4-6'
const normModel = (v: string): ClaudeModel =>
  (CLAUDE_MODELS as string[]).includes(v) ? (v as ClaudeModel) : DEFAULT_CLAUDE_MODEL

function friendlyError(e: any): string {
  const msg: string = e?.response?.data?.message || ''
  if (e?.response?.status === 403) return '권한이 없습니다 (AI 설정은 ADMIN 전용).'
  if (msg.includes('ERR-AI-400')) return msg.replace(/^ERR-AI-400:\s*/, '')
  return 'AI 설정을 처리하지 못했습니다.'
}

export default function AiPlatformSettings() {
  const [provider, setProvider] = useState<AiProvider>('ollama')
  const [claudeModel, setClaudeModel] = useState<ClaudeModel>(DEFAULT_CLAUDE_MODEL)
  const [claudeKeySet, setClaudeKeySet] = useState(false)
  const [ollamaTextModel, setOllamaTextModel] = useState('')
  const [aiEnabled, setAiEnabled] = useState(true)

  const [loading, setLoading] = useState(false)
  const [saving, setSaving] = useState(false)
  const [saved, setSaved] = useState(false)
  const [err, setErr] = useState('')

  const [testing, setTesting] = useState(false)
  const [testResult, setTestResult] = useState<AiTestResult | null>(null)

  const load = () => {
    setLoading(true)
    getAiConfig()
      .then(dto => {
        setProvider(dto.provider)
        setClaudeModel(normModel(dto.claudeModel ?? DEFAULT_CLAUDE_MODEL))
        setClaudeKeySet(!!dto.claudeKeySet)
        setOllamaTextModel(dto.ollamaTextModel ?? '')
        setAiEnabled(!!dto.aiEnabled)
        setErr('')
      })
      .catch(e => setErr(friendlyError(e)))
      .finally(() => setLoading(false))
  }

  useEffect(() => { load() }, [])

  const markDirty = () => { setSaved(false); setTestResult(null) }

  const submit = async () => {
    setSaving(true)
    setSaved(false)
    try {
      const dto = await updateAiConfig({ provider, claudeModel })
      setProvider(dto.provider)
      setClaudeModel(normModel(dto.claudeModel ?? DEFAULT_CLAUDE_MODEL))
      setClaudeKeySet(!!dto.claudeKeySet)
      setOllamaTextModel(dto.ollamaTextModel ?? '')
      setAiEnabled(!!dto.aiEnabled)
      setSaved(true)
      setErr('')
    } catch (e) {
      setErr(friendlyError(e))
    } finally {
      setSaving(false)
    }
  }

  const runTest = async () => {
    setTesting(true)
    setTestResult(null)
    try {
      setTestResult(await testAiConfig())
    } catch (e) {
      setTestResult({ ok: false, degraded: false, message: friendlyError(e) })
    } finally {
      setTesting(false)
    }
  }

  const isClaude = provider === 'claude'
  const isGlm = provider === 'glm'
  const showKeyFallback = isClaude && !claudeKeySet
  const showDisabledFallback = !isClaude && !aiEnabled

  const statusClass = testResult
    ? testResult.degraded
      ? 'text-amber-300'
      : testResult.ok
        ? 'text-emerald-300'
        : 'text-rose-300'
    : ''

  return (
    <div>
      <div className="flex items-center justify-between mb-6">
        <div>
          <h1 className="text-xl font-bold flex items-center gap-2">
            <Cpu size={20} className="text-brand" /> AI 플랫폼 설정
          </h1>
          <p className="text-sm text-gray-400 mt-1">
            알람 분석·POS 분류·채팅 등 텍스트 생성에 사용할 LLM 제공자와 모델을 선택합니다.
          </p>
        </div>
        <button
          onClick={load}
          disabled={loading}
          className="px-3 py-1.5 rounded-lg bg-card border border-edge text-sm disabled:opacity-40"
        >
          새로고침
        </button>
      </div>

      {err && (
        <div className="bg-rose-500/10 border border-rose-500/40 text-rose-300 text-sm rounded-lg px-4 py-2.5 mb-4">
          {err}
        </div>
      )}

      {(showKeyFallback || showDisabledFallback) && (
        <div className="bg-amber-500/10 border border-amber-500/40 text-amber-300 text-sm rounded-lg px-4 py-2.5 mb-4">
          {showKeyFallback
            ? 'Claude API 키가 설정되지 않아 Ollama(온프레미스)로 폴백 동작합니다. 서버 환경변수 ANTHROPIC_API_KEY 설정 후 사용하세요.'
            : 'AI 기능이 비활성 상태입니다. 모든 AI 결과는 규칙 기반(degraded)으로 동작합니다.'}
        </div>
      )}

      {isGlm && (
        <div className="bg-amber-500/10 border border-amber-500/40 text-amber-300 text-sm rounded-lg px-4 py-2.5 mb-4">
          GLM(glm4:9b)은 약 5.5GB 로드가 필요해 현재 서버 RAM 여유(~2.1GB)로는 콜드로드가 실패할 수 있습니다.
          선택은 가능하나 실패 시 Ollama 소형 모델로 자동 폴백합니다. RAM 증설 후 사용을 권장합니다.
        </div>
      )}

      <div className="grid gap-5 md:grid-cols-2">
        {/* ── 제공자 & 모델 ── */}
        <section className="bg-card border border-edge rounded-xl p-5">
          <h2 className="text-sm font-semibold mb-4 flex items-center gap-2">
            <Cpu size={16} className="text-brand" /> 제공자 & 모델
          </h2>

          <div className="grid grid-cols-2 gap-2 mb-4">
            {PROVIDERS.map(p => (
              <button
                key={p.id}
                onClick={() => { setProvider(p.id); markDirty() }}
                className={`text-left px-3 py-2.5 rounded-lg border text-sm transition-colors ${
                  provider === p.id
                    ? 'bg-brand/15 border-brand text-brand'
                    : 'bg-ink border-edge text-gray-300 hover:border-brand/50'
                }`}
              >
                <div className="font-semibold flex items-center gap-1.5">
                  {p.label}
                  {p.ram && (
                    <span className="text-[9px] px-1 py-0.5 rounded bg-amber-500/20 text-amber-300 border border-amber-500/40">
                      RAM
                    </span>
                  )}
                </div>
                <div className="text-[11px] text-gray-500 mt-0.5">{p.hint}</div>
              </button>
            ))}
          </div>

          {/* Ollama 계열 — 텍스트 모델 읽기 전용 표시 */}
          {!isClaude && (
            <div className="mb-4">
              <label className="block text-xs text-gray-500 mb-1">Ollama 텍스트 모델</label>
              <div className="px-3 py-2 rounded-lg bg-ink border border-edge text-sm font-mono">
                {ollamaTextModel || 'llama3.2:1b'}
              </div>
              <p className="text-[11px] text-gray-500 mt-1">
                온프레미스 모델 — provider 별로 고정. 외부 호출 없음.
              </p>
            </div>
          )}

          {/* Claude — 모델 셀렉트 + 키 배지(값 비노출) */}
          {isClaude && (
            <>
              <div className="mb-4">
                <label className="block text-xs text-gray-500 mb-1">Claude 모델</label>
                <select
                  value={claudeModel}
                  onChange={e => { setClaudeModel(normModel(e.target.value)); markDirty() }}
                  className="w-full px-3 py-2 rounded-lg bg-ink border border-edge text-sm focus:border-brand outline-none"
                >
                  {CLAUDE_MODELS.map(m => (
                    <option key={m} value={m}>{m}</option>
                  ))}
                </select>
              </div>
              <div className="mb-4">
                <label className="block text-xs text-gray-500 mb-1 flex items-center gap-1">
                  <KeyRound size={13} /> API 키
                </label>
                <span
                  className={`inline-block px-3 py-1 rounded-lg text-xs font-semibold ${
                    claudeKeySet
                      ? 'bg-emerald-500/15 text-emerald-300 border border-emerald-500/40'
                      : 'bg-rose-500/15 text-rose-300 border border-rose-500/40'
                  }`}
                >
                  {claudeKeySet ? '설정됨' : '미설정'}
                </span>
                <p className="text-[11px] text-gray-500 mt-1.5">
                  키는 서버 환경변수(ANTHROPIC_API_KEY)로만 주입되며 화면·응답·로그에 노출되지 않습니다.
                </p>
              </div>
            </>
          )}

          <div className="flex items-center gap-3">
            <button
              onClick={submit}
              disabled={saving || loading}
              className="flex items-center gap-1.5 px-4 py-2 rounded-lg bg-brand text-ink text-sm font-semibold disabled:opacity-40"
            >
              <Save size={15} /> {saving ? '저장 중…' : '저장'}
            </button>
            {saved && <span className="text-emerald-300 text-xs">저장됨</span>}
          </div>
        </section>

        {/* ── 연결 테스트 ── */}
        <section className="bg-card border border-edge rounded-xl p-5">
          <h2 className="text-sm font-semibold mb-2 flex items-center gap-2">
            <PlugZap size={16} className="text-brand" /> 연결 테스트
          </h2>
          <p className="text-sm text-gray-400 mb-4">
            저장된 설정 기준으로 선택한 제공자에 짧은 ping 을 보내 연결을 확인합니다(요약 결과만).
          </p>
          <div className="flex items-center gap-3">
            <button
              onClick={runTest}
              disabled={testing}
              className="px-4 py-2 rounded-lg bg-card border border-edge text-sm disabled:opacity-40 hover:border-brand/50"
            >
              {testing ? '테스트 중…' : '테스트 실행'}
            </button>
            {testResult && (
              <span className={`text-sm ${statusClass}`} role="status" aria-live="polite">
                {testResult.message}
              </span>
            )}
          </div>
          <p className="text-[11px] text-gray-500 mt-3">
            먼저 변경 사항을 저장한 뒤 테스트하세요. Claude 실패 시 Ollama 로 자동 폴백합니다.
          </p>
        </section>
      </div>
    </div>
  )
}
