<script setup>
import { ref, computed } from 'vue'
import DashboardLayout from '../layouts/DashboardLayout.vue'
import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { Textarea } from '@/components/ui/textarea'
import { Badge } from '@/components/ui/badge'
import { Separator } from '@/components/ui/separator'
import { ScrollArea } from '@/components/ui/scroll-area'
import { Tabs, TabsContent, TabsList, TabsTrigger } from '@/components/ui/tabs'

const sleep = ms => new Promise(r => setTimeout(r, ms))

const INITIAL_PROMPT = `Bạn là trợ lý tư vấn thời trang của Canifa. Hãy trả lời câu hỏi của khách hàng một cách thân thiện và chuyên nghiệp.

Hướng dẫn:
- Luôn chào hỏi thân thiện, xưng "bạn"
- Khi khách hỏi về sản phẩm, gọi tool data_retrieval_tool để tìm kiếm
- KHÔNG được bịa sản phẩm, giá, khuyến mãi không có thật
- Nếu khách chưa rõ nhu cầu, hỏi thêm để tư vấn chính xác
- Trả lời bằng tiếng Việt, ngôn ngữ tự nhiên`

const DEFAULT_TESTS = [
  { id: 1, input: 'Tôi muốn mua áo đi làm, không biết chọn màu gì?', expect_keywords: ['màu', 'công sở', 'phong cách'], expect_question: true },
  { id: 2, input: 'Shop có váy dự tiệc không?', expect_keywords: ['dạ', 'có', 'màu'], expect_question: true },
  { id: 3, input: 'Ngân sách 500k mua được gì?', expect_keywords: ['500', 'sản phẩm', 'gợi ý'], expect_question: false },
  { id: 4, input: 'Áo khoác nào hợp mùa đông?', expect_keywords: ['ấm', 'chất liệu', 'kiểu'], expect_question: true },
  { id: 5, input: 'Tôi cao 1m55 nặng 50kg mặc size gì?', expect_keywords: ['size', 'S', 'M'], expect_question: false },
]

const currPrompt = ref(INITIAL_PROMPT)
const editingPrompt = ref(false)
const editPromptDraft = ref('')
const promptVer = ref(1)
const promptHistory = ref([{ v: 1, prompt: INITIAL_PROMPT, avgScore: null, changes: [] }])
const testCases = ref([...DEFAULT_TESTS])
const results = ref({})
const running = ref(false)
const paused = ref(false)
const iterations = ref(0)
const scoreHistory = ref([])
const logs = ref([])
const selectedId = ref(null)
const activeId = ref(null)
const autoApply = ref(true)
const proposal = ref(null)
const latestMet = ref(null)
const tab = ref('tests')

const latestScore = computed(() => scoreHistory.value.length ? scoreHistory.value[scoreHistory.value.length - 1] : null)
const avgScore = computed(() => latestScore.value)

function pillClass(v) { return v >= 0.75 ? 'bg-green-100 text-green-700' : v >= 0.5 ? 'bg-amber-100 text-amber-700' : 'bg-red-100 text-red-700' }
function ts() { return new Date().toLocaleTimeString('vi-VN', { hour: '2-digit', minute: '2-digit', second: '2-digit' }) }
function addLog(msg, type = 'info') {
  logs.value.push({ msg, type, t: ts() })
  if (logs.value.length > 120) logs.value = logs.value.slice(-100)
}

function logColor(type) {
  const map = { system: 'text-amber-700', run: 'text-orange-700', score: 'text-green-700', optimize: 'text-purple-700', pass: 'text-green-700', fail: 'text-red-600', info: 'text-gray-500' }
  return map[type] || 'text-gray-500'
}

async function apiRunTest(prompt, testInput) {
  const r = await fetch('/api/prompt-optimizer/run-test', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ prompt, test_input: testInput }) })
  return r.json()
}

async function apiJudge(testInput, chatbotOutput, productIds, expectKw, expectQ) {
  const r = await fetch('/api/prompt-optimizer/judge', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ test_input: testInput, chatbot_output: chatbotOutput, product_ids: productIds, expect_keywords: expectKw, expect_question: expectQ }) })
  return r.json()
}

async function apiOptimize(currentPrompt, testResults, version) {
  const r = await fetch('/api/prompt-optimizer/optimize', { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify({ current_prompt: currentPrompt, test_results: testResults, version }) })
  return r.json()
}

async function runRound() {
  const roundResults = {}
  const allMet = { factual: 0, relevance: 0, tone: 0, helpfulness: 0, hallucination: 0 }
  addLog(`Round ${iterations.value + 1} — Prompt v${promptVer.value} — ${testCases.value.length} tests`, 'system')

  for (const tc of testCases.value) {
    if (!running.value) break
    while (paused.value && running.value) await sleep(200)
    activeId.value = tc.id
    results.value[tc.id] = { output: '', total: null, metrics: null, streaming: true }
    addLog(`Testing #${tc.id}: "${tc.input.slice(0, 40)}..."`, 'run')

    let chatResult
    try {
      chatResult = await apiRunTest(currPrompt.value, tc.input)
      if (chatResult.status !== 'success') throw new Error(chatResult.message || 'API error')
    } catch (e) {
      addLog(`Error: ${e.message}`, 'fail')
      results.value[tc.id] = { output: 'Error: ' + e.message, total: 0, metrics: null, streaming: false }
      continue
    }

    results.value[tc.id] = { output: chatResult.output, total: null, metrics: null, streaming: true }

    let judgeResult
    try {
      judgeResult = await apiJudge(tc.input, chatResult.output, chatResult.product_ids || [], tc.expect_keywords, tc.expect_question)
      if (judgeResult.status !== 'success') throw new Error(judgeResult.message || 'Judge error')
    } catch (e) {
      addLog(`Judge error: ${e.message}`, 'fail')
      results.value[tc.id] = { ...results.value[tc.id], total: 0.5, metrics: null, streaming: false }
      roundResults[tc.id] = { input: tc.input, output: chatResult.output, score: 0.5, reasoning: '', issues: [] }
      continue
    }

    const total = judgeResult.total || 0
    results.value[tc.id] = { output: chatResult.output, total, metrics: judgeResult.metrics || {}, reasoning: judgeResult.reasoning || '', issues: judgeResult.issues || [], streaming: false }
    roundResults[tc.id] = { input: tc.input, output: chatResult.output, score: total, reasoning: judgeResult.reasoning || '', issues: judgeResult.issues || [] }
    Object.keys(allMet).forEach(k => { if (judgeResult.metrics?.[k] != null) allMet[k] += judgeResult.metrics[k] / testCases.value.length })
    addLog(`${total >= 0.75 ? 'PASS' : total >= 0.5 ? 'WARN' : 'FAIL'} #${tc.id} Score: ${(total * 100).toFixed(0)}%`, total >= 0.75 ? 'pass' : 'fail')
  }

  activeId.value = null
  const scores = Object.values(roundResults)
  const avg = scores.reduce((s, r) => s + r.score, 0) / Math.max(scores.length, 1)
  scoreHistory.value.push(parseFloat(avg.toFixed(3)))
  iterations.value++
  latestMet.value = { ...allMet }
  addLog(`Avg: ${(avg * 100).toFixed(1)}% — v${promptVer.value}`, 'score')
  promptHistory.value = promptHistory.value.map(h => h.v === promptVer.value ? { ...h, avgScore: avg } : h)
  return { roundResults, avg }
}

async function doOptimize(roundResults) {
  addLog('Score < 75% — Optimizer đang phân tích...', 'optimize')
  const testResults = Object.values(roundResults)
  try {
    const result = await apiOptimize(currPrompt.value, testResults, promptVer.value)
    if (result.status !== 'success') throw new Error(result.message)
    addLog((result.analysis || '').slice(0, 70) + '...', 'optimize')
    ;(result.changes || []).forEach(c => addLog(`→ ${c}`, 'optimize'))
    if (autoApply.value) {
      promptVer.value++
      currPrompt.value = result.new_prompt
      promptHistory.value.push({ v: promptVer.value, prompt: result.new_prompt, avgScore: null, changes: result.changes || [] })
      addLog(`Prompt v${promptVer.value} applied!`, 'system')
    } else {
      proposal.value = result
    }
  } catch (e) { addLog(`Optimizer error: ${e.message}`, 'fail') }
}

async function startLoop() {
  if (running.value) return
  running.value = true; paused.value = false
  results.value = {}; scoreHistory.value = []; iterations.value = 0
  latestMet.value = null; activeId.value = null; selectedId.value = null
  logs.value = []; proposal.value = null
  tab.value = 'log'
  addLog('Optimizer khởi động', 'system')
  addLog(`${testCases.value.length} test cases · Target >= 75%`, 'info')

  let round = 0
  while (running.value && round < 6) {
    round++
    const { roundResults, avg } = await runRound()
    if (!running.value) break
    if (avg >= 0.75) { addLog(`Target đạt! ${(avg * 100).toFixed(1)}% >= 75%`, 'pass'); break }
    if (round < 6) { await doOptimize(roundResults); await sleep(800) }
    else addLog(`Max rounds. Best: ${(Math.max(...scoreHistory.value) * 100).toFixed(1)}%`, 'system')
  }
  running.value = false; paused.value = false
  addLog('Done', 'system')
}

function stopLoop() { running.value = false; paused.value = false; addLog('Stopped', 'info') }
function togglePause() { paused.value = !paused.value; addLog(paused.value ? 'Paused' : 'Resumed', 'info') }

function addNewTC() {
  const input = window.prompt('Nhập câu hỏi test:')
  if (!input) return
  const kw = (window.prompt('Keywords (cách bởi dấu phẩy):') || '').split(',').map(s => s.trim()).filter(Boolean)
  const q = window.confirm('Mong bot hỏi lại khách?')
  testCases.value.push({ id: Date.now(), input, expect_keywords: kw, expect_question: q })
  addLog('Test case mới thêm', 'info')
}

function deleteTC(id) {
  testCases.value = testCases.value.filter(t => t.id !== id)
  delete results.value[id]
  addLog(`Test #${id} đã xoá`, 'info')
}

function restoreVersion(v) {
  if (running.value) return
  const h = promptHistory.value.find(x => x.v === v)
  if (!h) return
  currPrompt.value = h.prompt; promptVer.value = h.v
  addLog(`Restored v${v}`, 'info')
}

function applyProposal() {
  if (!proposal.value) return
  promptVer.value++
  currPrompt.value = proposal.value.new_prompt
  promptHistory.value.push({ v: promptVer.value, prompt: proposal.value.new_prompt, avgScore: null, changes: proposal.value.changes || [] })
  proposal.value = null
}
</script>

<template>
  <DashboardLayout>
    <div class="p-5 max-w-7xl space-y-4">
      <!-- Header -->
      <div class="flex items-center justify-between">
        <div>
          <h1 class="text-2xl font-black text-gray-900">🔬 Prompt Optimizer</h1>
          <p class="text-xs text-gray-500 mt-0.5">Tự động eval và cải thiện prompt qua nhiều vòng</p>
        </div>
        <div class="flex items-center gap-2">
          <div :class="['flex items-center gap-1.5 text-xs px-2 py-1 rounded-full',
            running && !paused ? 'bg-green-100 text-green-700' :
            running && paused ? 'bg-amber-100 text-amber-700' :
            iterations > 0 ? 'bg-green-100 text-green-700' : 'bg-gray-100 text-gray-500']">
            <span :class="['w-1.5 h-1.5 rounded-full', running && !paused ? 'bg-green-500 animate-pulse' : 'bg-gray-300']"></span>
            {{ running && !paused ? 'Running' : running && paused ? 'Paused' : iterations > 0 ? 'Done' : 'Ready' }}
          </div>
          <span class="text-xs text-gray-400">v{{ promptVer }} · Round {{ iterations || '—' }} · {{ latestScore != null ? (latestScore * 100).toFixed(1) + '%' : '—' }}</span>
          <Button v-if="!running" size="sm" @click="startLoop">▶ Chạy</Button>
          <Button v-if="running" size="sm" variant="outline" @click="togglePause">{{ paused ? '▶ Resume' : '⏸ Pause' }}</Button>
          <Button v-if="running" size="sm" variant="destructive" @click="stopLoop">⏹ Stop</Button>
        </div>
      </div>

      <div class="grid grid-cols-[300px_1fr_280px] gap-4 h-[calc(100vh-160px)]">

        <!-- Left: Tests + Versions + Log -->
        <div class="flex flex-col">
          <Tabs v-model="tab" class="flex flex-col flex-1">
            <TabsList class="grid grid-cols-3 w-full">
              <TabsTrigger value="tests">Tests</TabsTrigger>
              <TabsTrigger value="versions">Versions</TabsTrigger>
              <TabsTrigger value="log">Log</TabsTrigger>
            </TabsList>
            <TabsContent value="tests" class="flex-1 overflow-hidden mt-0">
              <ScrollArea class="h-full mt-2">
                <div class="space-y-1.5 pr-1">
                  <div v-for="tc in testCases" :key="tc.id"
                       @click="selectedId = selectedId === tc.id ? null : tc.id"
                       :class="['border rounded-xl p-2.5 cursor-pointer transition-all',
                         activeId === tc.id ? 'border-amber-400 bg-amber-50 animate-pulse' :
                         selectedId === tc.id ? 'border-blue-300 bg-blue-50/40' :
                         results[tc.id]?.total != null ? 'border-gray-100' : 'border-gray-100 bg-white']">
                    <div class="flex items-start gap-2">
                      <p class="text-xs flex-1 leading-snug text-gray-700">{{ tc.input }}</p>
                      <div class="flex items-center gap-1 shrink-0">
                        <span v-if="results[tc.id]?.total != null"
                              :class="['text-[10px] px-1.5 py-0.5 rounded-full font-bold', pillClass(results[tc.id].total)]">
                          {{ (results[tc.id].total * 100).toFixed(0) }}%
                        </span>
                        <button @click.stop="deleteTC(tc.id)" class="text-gray-300 hover:text-red-400 text-xs">✕</button>
                      </div>
                    </div>
                    <div class="flex gap-1 mt-1.5 flex-wrap">
                      <span v-for="kw in tc.expect_keywords" :key="kw"
                            class="text-[9px] bg-gray-100 text-gray-500 px-1 py-0.5 rounded">{{ kw }}</span>
                      <span v-if="tc.expect_question" class="text-[9px] bg-amber-100 text-amber-600 px-1 py-0.5 rounded">?</span>
                    </div>
                  </div>
                  <button @click="addNewTC"
                          class="w-full py-2 border border-dashed border-gray-200 rounded-xl text-xs text-gray-400 hover:text-gray-600 hover:border-gray-300 transition-colors">
                    + Add test case
                  </button>
                </div>
              </ScrollArea>
            </TabsContent>
            <TabsContent value="versions" class="flex-1 overflow-hidden mt-0">
              <ScrollArea class="h-full mt-2">
                <div class="space-y-2 pr-1">
                  <div v-for="h in [...promptHistory].reverse()" :key="h.v"
                       @click="restoreVersion(h.v)"
                       :class="['border rounded-xl p-2.5 cursor-pointer transition-all',
                         h.v === promptVer ? 'border-amber-300 bg-amber-50' : 'border-gray-100 hover:bg-gray-50']">
                    <div class="flex items-center justify-between mb-1">
                      <span :class="['text-xs font-bold', h.v === promptVer ? 'text-amber-700' : 'text-gray-700']">v{{ h.v }}</span>
                      <div class="flex items-center gap-1.5">
                        <span v-if="h.avgScore != null" :class="['text-[10px] px-1.5 py-0.5 rounded-full font-bold', pillClass(h.avgScore)]">
                          {{ (h.avgScore * 100).toFixed(0) }}%
                        </span>
                        <Badge v-if="h.v === promptVer" class="text-[9px] h-4 bg-amber-100 text-amber-700 border-0">CURRENT</Badge>
                      </div>
                    </div>
                    <div v-for="c in h.changes?.slice(0, 2)" :key="c" class="text-[10px] text-gray-500 truncate">→ {{ c }}</div>
                    <span v-if="h.v === 1" class="text-[10px] text-gray-300">Initial prompt</span>
                  </div>
                </div>
              </ScrollArea>
            </TabsContent>
            <TabsContent value="log" class="flex-1 overflow-hidden mt-0">
              <ScrollArea class="h-full mt-2">
                <div v-if="!logs.length" class="text-center py-8 text-xs text-gray-300">No logs yet</div>
                <div v-for="(l, i) in logs" :key="i" class="flex items-start gap-2 py-0.5">
                  <span :class="['text-[9px] text-gray-300 shrink-0 mt-0.5']">{{ l.t }}</span>
                  <span :class="['text-[10px] flex-1', logColor(l.type)]">{{ l.msg }}</span>
                </div>
              </ScrollArea>
            </TabsContent>
          </Tabs>
        </div>

        <!-- Center: Prompt + Detail -->
        <div class="flex flex-col gap-3">
          <!-- Current Prompt -->
          <Card>
            <CardHeader class="pb-2 pt-3 px-4">
              <div class="flex items-center justify-between">
                <span class="text-xs font-bold text-gray-700">System Prompt <Badge variant="outline" class="text-[9px] ml-1">v{{ promptVer }}</Badge></span>
                <Button variant="ghost" size="sm" class="h-6 text-[10px]"
                        @click="if (!running) { editingPrompt = !editingPrompt; editPromptDraft = currPrompt }">
                  {{ editingPrompt ? 'Cancel' : 'Edit' }}
                </Button>
              </div>
            </CardHeader>
            <CardContent class="px-4 pb-3">
              <Textarea v-if="editingPrompt" v-model="editPromptDraft" class="text-xs font-mono min-h-[120px]" />
              <pre v-else class="text-xs text-gray-600 font-mono whitespace-pre-wrap leading-relaxed max-h-32 overflow-hidden line-clamp-6">{{ currPrompt }}</pre>
              <Button v-if="editingPrompt" size="sm" class="mt-2" @click="currPrompt = editPromptDraft; editingPrompt = false">Apply</Button>
            </CardContent>
          </Card>

          <!-- Proposal -->
          <Card v-if="proposal" class="border-purple-200 bg-purple-50/30">
            <CardContent class="p-4">
              <div class="flex items-center justify-between mb-2">
                <span class="text-xs font-bold text-purple-700">💡 Optimizer Proposal</span>
              </div>
              <div v-for="c in (proposal.changes || []).slice(0, 3)" :key="c" class="text-[10px] text-purple-600 mb-0.5">→ {{ c }}</div>
              <div class="flex gap-2 mt-3">
                <Button size="sm" @click="applyProposal">✅ Apply v{{ promptVer + 1 }}</Button>
                <Button size="sm" variant="outline" @click="proposal = null">Dismiss</Button>
              </div>
            </CardContent>
          </Card>

          <!-- Detail for selected test -->
          <Card class="flex-1 overflow-hidden">
            <CardContent class="p-4 h-full">
              <div v-if="!selectedId || !results[selectedId]" class="flex items-center justify-center h-full text-gray-400 text-xs">
                Click test case để xem chi tiết
              </div>
              <div v-else class="space-y-3">
                <div class="flex items-center justify-between">
                  <span class="font-bold text-sm text-gray-800">Test #{{ selectedId }}</span>
                  <span v-if="results[selectedId].total != null"
                        :class="['text-sm font-black', pillClass(results[selectedId].total).includes('green') ? 'text-green-700' : pillClass(results[selectedId].total).includes('amber') ? 'text-amber-700' : 'text-red-600']">
                    {{ (results[selectedId].total * 100).toFixed(0) }}%
                  </span>
                </div>
                <div class="text-xs text-gray-500 bg-gray-50 p-2 rounded">{{ testCases.find(t => t.id === selectedId)?.input }}</div>
                <div v-if="results[selectedId].output" class="text-xs text-gray-700 bg-white border border-gray-100 p-3 rounded-lg max-h-40 overflow-y-auto leading-relaxed">
                  {{ results[selectedId].output }}
                </div>
                <div v-if="results[selectedId].metrics" class="space-y-1.5">
                  <p class="text-[10px] font-bold text-gray-400 uppercase">Metrics</p>
                  <div v-for="(v, k) in results[selectedId].metrics" :key="k" class="space-y-0.5">
                    <div class="flex justify-between text-[10px]">
                      <span class="text-gray-500">{{ k }}</span>
                      <span :class="v >= 0.75 ? 'text-green-600' : v >= 0.5 ? 'text-amber-600' : 'text-red-600'" class="font-bold">{{ (v * 100).toFixed(0) }}%</span>
                    </div>
                    <div class="h-1 bg-gray-100 rounded-full overflow-hidden">
                      <div :class="['h-full rounded-full', v >= 0.75 ? 'bg-green-500' : v >= 0.5 ? 'bg-amber-500' : 'bg-red-500']" :style="{ width: (v * 100) + '%' }"></div>
                    </div>
                  </div>
                </div>
                <div v-if="results[selectedId].reasoning" class="text-[10px] text-gray-600 bg-gray-50 p-2 rounded italic leading-relaxed">
                  {{ results[selectedId].reasoning }}
                </div>
              </div>
            </CardContent>
          </Card>
        </div>

        <!-- Right: Metrics + Score trend -->
        <div class="space-y-3">
          <Card>
            <CardContent class="p-4 space-y-4">
              <div class="text-center">
                <p :class="['text-3xl font-black', avgScore != null ? (avgScore >= 0.75 ? 'text-green-700' : avgScore >= 0.5 ? 'text-amber-700' : 'text-red-700') : 'text-gray-300']">
                  {{ avgScore != null ? (avgScore * 100).toFixed(1) + '%' : '—' }}
                </p>
                <p class="text-[10px] text-gray-400">Avg Score</p>
              </div>
              <div class="text-center">
                <p class="text-xl font-black text-gray-700">{{ iterations || '—' }}</p>
                <p class="text-[10px] text-gray-400">Rounds</p>
              </div>
              <Separator />
              <div class="flex items-center gap-2">
                <input id="auto-apply" type="checkbox" v-model="autoApply" class="accent-amber-600" />
                <label for="auto-apply" class="text-xs text-gray-600">Auto apply proposals</label>
              </div>
            </CardContent>
          </Card>

          <!-- Score sparkline (simple bars) -->
          <Card v-if="scoreHistory.length >= 2">
            <CardContent class="p-4">
              <p class="text-[10px] text-gray-400 font-bold uppercase mb-2">Score Trend</p>
              <div class="flex items-end gap-1 h-12">
                <div v-for="(s, i) in scoreHistory" :key="i"
                     :class="['flex-1 rounded-t transition-all', s >= 0.75 ? 'bg-green-500' : s >= 0.5 ? 'bg-amber-500' : 'bg-red-500']"
                     :style="{ height: (s * 100) + '%' }"
                     :title="`Round ${i + 1}: ${(s * 100).toFixed(1)}%`"></div>
              </div>
            </CardContent>
          </Card>

          <!-- Metrics panel -->
          <Card v-if="latestMet">
            <CardContent class="p-4">
              <p class="text-[10px] text-gray-400 font-bold uppercase mb-2">Last Round Metrics</p>
              <div v-for="(v, k) in latestMet" :key="k" class="space-y-0.5 mb-2">
                <div class="flex justify-between text-[10px]">
                  <span class="text-gray-500">{{ k }}</span>
                  <span :class="v >= 0.75 ? 'text-green-600' : v >= 0.5 ? 'text-amber-600' : 'text-red-600'" class="font-bold">{{ (v * 100).toFixed(0) }}%</span>
                </div>
                <div class="h-1 bg-gray-100 rounded-full overflow-hidden">
                  <div :class="['h-full rounded-full', v >= 0.75 ? 'bg-green-500' : v >= 0.5 ? 'bg-amber-500' : 'bg-red-500']" :style="{ width: (v * 100) + '%' }"></div>
                </div>
              </div>
            </CardContent>
          </Card>
        </div>
      </div>
    </div>
  </DashboardLayout>
</template>
