'use client';

// Mira 對話核心元件（河道右側 dock 與 /mira/chat 單頁共用）
// SDD: polaris/mira/.agents/specs/mira-app/design.md §3.6.5
// RAG：提問先語義搜尋 KBDB（wiki + 河道）取 context → claude-api daemon。
// 重要：context 空時 prompt 明確要求「只說沒有相關筆記」，避免 daemon 自由發揮（曾幻想 OpenWebUI）

import { useEffect, useRef, useState } from 'react';
import Link from 'next/link';
import { MarkdownView } from './markdown';

const KBDB_BASE = 'https://kbdb.finally.click';
const API_BASE = process.env.NEXT_PUBLIC_API_BASE ?? 'https://cypher.arcrun.dev';
const CLAUDE_API = 'https://claude-api.arcrun.dev';

type Source = { label: string; href: string };
type Msg = { role: 'user' | 'mira'; text: string; sources?: Source[]; pending?: boolean };

type SearchMatch = {
  score: number;
  type: 'block' | 'triplet';
  block: { id: string; page_name: string | null; content: string | null; type: string } | null;
  triplet: { subject?: string; predicate?: string; object?: string } | null;
};

// 繁體異體字正規化（臺→台 等），讓 query 跟 KB 內容（多用「台」）對得上
function normalizeQuery(q: string): string {
  return q.replace(/臺/g, '台');
}

async function fetchContext(apiKey: string, query: string): Promise<{ context: string; sources: Source[] }> {
  try {
    const res = await fetch(`${KBDB_BASE}/search`, {
      method: 'POST',
      headers: { 'Content-Type': 'application/json', Authorization: `Bearer ${apiKey}` },
      body: JSON.stringify({ query: normalizeQuery(query), type: 'semantic', topK: 8 }),
    });
    if (!res.ok) return { context: '', sources: [] };
    const data = (await res.json()) as { matches?: SearchMatch[] };
    const parts: string[] = [];
    const sources: Source[] = [];
    for (const m of data.matches ?? []) {
      if (m.block?.content) {
        const b = m.block;
        parts.push(`### ${b.type}：${b.page_name ?? b.id}\n${b.content}`);
        if (b.type === 'wiki-page' && b.page_name) {
          sources.push({ label: `📚 ${(b.content || b.page_name).slice(0, 20)}`, href: `/mira/wiki/${encodeURIComponent(b.page_name)}` });
        } else if (b.page_name) {
          sources.push({ label: `🌊 ${(b.content || '').slice(0, 20) || b.page_name}`, href: `/mira/feed#page=${encodeURIComponent(b.page_name)}` });
        }
      } else if (m.triplet) {
        const t = m.triplet;
        parts.push(`關係：${t.subject} >> ${t.predicate} >> ${t.object}`);
      }
    }
    const seen = new Set<string>();
    const uniq = sources.filter(s => (seen.has(s.href) ? false : (seen.add(s.href), true)));
    return { context: parts.join('\n\n'), sources: uniq.slice(0, 5) };
  } catch {
    return { context: '', sources: [] };
  }
}

function buildPrompt(history: Msg[], context: string, question: string): string {
  const convo = history
    .filter(m => !m.pending)
    .map(m => `${m.role === 'user' ? 'leo' : 'Mira'}：${m.text}`)
    .join('\n');
  const persona =
    `你是 Mira，leo 的個人知識庫副駕 AI。你只能根據下方「知識庫」與「對話脈絡」回答，` +
    `沒有任何外部系統存取權（沒有 OpenWebUI、沒有檔案系統、沒有別的工具）。\n\n`;
  const kb = context
    ? `## 知識庫（跟本次提問相關的 wiki / 河道內容）\n\n${context}\n\n`
    : `## 知識庫\n（這次在 leo 的筆記裡找不到相關內容。）\n\n`;
  const rules = context
    ? `規則：繁體中文（台灣用語）、務實不客套、優先引用上方知識庫並說「你之前寫過⋯」、簡短切題。`
    : `規則：繁體中文。**明確告訴 leo「你的筆記裡目前沒有關於這個的內容」**，` +
      `可以再用常識補一兩句（要標明那不是來自他的筆記），不要假裝有資料、不要編造系統或工具。`;
  return (
    persona +
    kb +
    (convo ? `## 對話脈絡\n${convo}\n\n` : '') +
    `---\n\nleo 現在問：「${question}」\n\n${rules}`
  );
}

export default function MiraChat({ compact = false }: { compact?: boolean }) {
  const [apiKey, setApiKey] = useState<string | null>(null);
  const [msgs, setMsgs] = useState<Msg[]>([]);
  const [input, setInput] = useState('');
  const [sending, setSending] = useState(false);
  const logRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    fetch(`${API_BASE}/me`, { credentials: 'include' })
      .then(r => (r.ok ? r.json() : null))
      .then((me: { api_key: string } | null) => { if (me?.api_key) setApiKey(me.api_key); })
      .catch(() => {});
  }, []);

  useEffect(() => {
    logRef.current?.scrollTo({ top: logRef.current.scrollHeight, behavior: 'smooth' });
  }, [msgs]);

  const send = async () => {
    const question = input.trim();
    if (!question || sending || !apiKey) return;
    setInput('');
    setSending(true);
    const history = msgs;
    setMsgs(m => [...m, { role: 'user', text: question }, { role: 'mira', text: '', pending: true }]);
    try {
      const { context, sources } = await fetchContext(apiKey, question);
      const prompt = buildPrompt(history, context, question);
      const res = await fetch(CLAUDE_API, {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({ prompt, timeout_ms: 60000 }),
      });
      const data = (await res.json()) as { success?: boolean; pending?: boolean; data?: { text?: string }; error?: string };
      let text: string;
      if (!res.ok || !data.success) text = `（回答失敗：${data.error ?? res.status}）`;
      else if (data.pending) text = '（Mira 還在想，daemon 切到背景模式，請稍後再問一次）';
      else text = data.data?.text ?? '（沒有內容）';
      setMsgs(m => {
        const next = [...m];
        next[next.length - 1] = { role: 'mira', text, sources: sources.length ? sources : undefined };
        return next;
      });
    } catch (e) {
      setMsgs(m => {
        const next = [...m];
        next[next.length - 1] = { role: 'mira', text: `（錯誤：${e instanceof Error ? e.message : String(e)}）` };
        return next;
      });
    } finally {
      setSending(false);
    }
  };

  return (
    <div className={`mira-chat${compact ? ' is-compact' : ''}`}>
      <div className="mira-chat-log" ref={logRef}>
        {msgs.length === 0 && (
          <div className="empty-state" style={{ marginTop: 28 }}>
            <div style={{ fontSize: 40, marginBottom: 8 }}>💬</div>
            <p style={{ color: 'var(--mira-text-2)', fontSize: 13 }}>問 Mira 任何事 — 它會先翻你的知識庫。</p>
          </div>
        )}
        {msgs.map((m, i) => (
          <div key={i} className={`mira-chat-msg ${m.role === 'user' ? 'is-user' : 'is-mira'}`}>
            <div className="mira-chat-bubble">
              {m.pending ? (
                <span className="mira-thinking-dots">Mira 思考中</span>
              ) : m.role === 'mira' ? (
                <MarkdownView text={m.text} />
              ) : (
                m.text
              )}
              {m.sources && m.sources.length > 0 && (
                <div className="mira-chat-sources">
                  來源：
                  {m.sources.map((s, j) => (
                    <span key={j}>
                      {j > 0 && ' · '}
                      <Link href={s.href}>{s.label}</Link>
                    </span>
                  ))}
                </div>
              )}
            </div>
          </div>
        ))}
      </div>

      <div className="mira-chat-input-row">
        <textarea
          className="mira-chat-input"
          value={input}
          onChange={e => setInput(e.target.value)}
          onKeyDown={e => {
            if ((e.metaKey || e.ctrlKey) && e.key === 'Enter') { e.preventDefault(); void send(); }
          }}
          placeholder="問 Mira…（⌘+Enter 送出）"
          rows={2}
          disabled={sending || !apiKey}
        />
        <button
          type="button"
          className="mira-btn-primary"
          onClick={() => void send()}
          disabled={sending || !apiKey || !input.trim()}
        >
          {sending ? '⋯' : '送出'}
        </button>
      </div>
    </div>
  );
}
