import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
  type ReactNode,
} from "react";
import { useLocation } from "react-router-dom";
import {
  aiApi,
  type AIFocus,
  type AIContextPayload,
  type AIProviderId,
  type AIStatus,
} from "../lib/ai";

export type ChatMessage = {
  id: string;
  role: "user" | "assistant" | "system";
  text: string;
  meta?: string;
};

type OpenAIOpts = {
  question?: string;
  focus?: AIFocus;
  send?: boolean;
};

type AIContextValue = {
  open: boolean;
  busy: boolean;
  messages: ChatMessage[];
  draft: string;
  setDraft: (v: string) => void;
  focus: AIFocus | null;
  contextLabel: string;
  status: AIStatus | null;
  provider: AIProviderId;
  setProvider: (p: AIProviderId) => void;
  model: string;
  setModel: (m: string) => void;
  openAI: (opts?: OpenAIOpts) => void;
  closeAI: () => void;
  sendMessage: (question?: string, focusOverride?: AIFocus | null, skillId?: string) => Promise<void>;
  clearChat: () => void;
  refreshStatus: () => Promise<void>;
};

const AIContext = createContext<AIContextValue | null>(null);

function routeToView(pathname: string): string {
  if (pathname === "/") return "hub";
  if (pathname === "/market") return "market";
  if (pathname === "/research") return "stock";
  if (pathname === "/settings") return "settings";
  if (pathname === "/skills") return "skills";
  if (pathname === "/patterns") return "patterns";
  return "hub";
}

const VIEW_LABELS: Record<string, string> = {
  hub: "今日基地",
  market: "市場世界",
  stock: "個股背包",
  skills: "心法技能樹",
  patterns: "線型圖鑑",
  settings: "設定",
};

export function AIProvider({ children }: { children: ReactNode }) {
  const location = useLocation();
  const [open, setOpen] = useState(false);
  const [busy, setBusy] = useState(false);
  const [messages, setMessages] = useState<ChatMessage[]>([
    {
      id: "welcome",
      role: "assistant",
      text: "咕嗚——歡迎來到 MacroScope！\n我是導覽員「金幣貓頭鷹」。有頁面資料時會一併附上；人設與技能可在「設定 → 導覽員」調整。",
      meta: "導覽員",
    },
  ]);
  const [draft, setDraft] = useState("");
  const [focus, setFocus] = useState<AIFocus | null>(null);
  const [contextLabel, setContextLabel] = useState("準備中");
  const [status, setStatus] = useState<AIStatus | null>(null);
  const [provider, setProvider] = useState<AIProviderId>("grok");
  const [model, setModel] = useState("");

  const refreshStatus = useCallback(async () => {
    try {
      const s = await aiApi.status();
      setStatus(s);
      const active = s.providers.find((p) => p.active && p.hasKey) || s.providers.find((p) => p.hasKey);
      if (active) {
        setProvider(active.id);
        if (!model && active.model) setModel(active.model);
      }
    } catch {
      setStatus(null);
    }
  }, [model]);

  const collectContext = useCallback(
    async (f?: AIFocus | null): Promise<AIContextPayload> => {
      const view = routeToView(location.pathname);
      if (view === "settings") {
        return { view, focus: {}, hasPageData: false, mode: "chat" };
      }
      const mergedFocus: AIFocus = {
        ...f,
        view,
        tab: f?.tab,
        cardTitle: f?.cardTitle || f?.label,
      };
      try {
        const client: Record<string, unknown> = {
          pathname: location.pathname,
          hash: location.hash,
        };
        if (mergedFocus.symbol) client.symbol = mergedFocus.symbol;
        const ctx = await aiApi.context(view, mergedFocus, client);
        return ctx;
      } catch (e) {
        return {
          view,
          focus: mergedFocus,
          hasPageData: false,
          mode: "chat",
          contextError: e instanceof Error ? e.message : String(e),
        };
      }
    },
    [location.pathname, location.hash]
  );

  const updateContextLabel = useCallback(
    async (f?: AIFocus | null) => {
      const view = routeToView(location.pathname);
      if (view === "settings") {
        setContextLabel("一般聊天");
        return;
      }
      setContextLabel("正在讀取頁面資料…");
      const ctx = await collectContext(f);
      const label = VIEW_LABELS[view] || "頁面";
      const chip = f?.cardTitle || f?.label;
      if (ctx.hasPageData) {
        setContextLabel(chip ? `已附上 ${label} · ${chip}` : `已附上 ${label} 資料`);
      } else if (ctx.contextError) {
        setContextLabel(`一般聊天（資料未取得）`);
      } else {
        setContextLabel(`一般聊天（${label}）`);
      }
    },
    [collectContext, location.pathname]
  );

  const sendMessage = useCallback(
    async (question?: string, focusOverride?: AIFocus | null, skillId?: string) => {
      const q = (question ?? draft).trim();
      const activeFocus = focusOverride !== undefined ? focusOverride : focus;
      if (!q || busy) return;
      if (!status?.ready) {
        setMessages((m) => [
          ...m,
          {
            id: `err-${Date.now()}`,
            role: "system",
            text: "尚未設定 AI API Key。請到「設定 → AI Provider」填入 Grok 或 OpenCode Go 金鑰。",
          },
        ]);
        setOpen(true);
        return;
      }

      setBusy(true);
      setDraft("");
      const userMsg: ChatMessage = { id: `u-${Date.now()}`, role: "user", text: q };
      const typingId = `t-${Date.now()}`;
      setMessages((m) => [
        ...m,
        userMsg,
        { id: typingId, role: "assistant", text: "…", meta: "思考中" },
      ]);

      try {
        const ctx = await collectContext(activeFocus);
        await updateContextLabel(activeFocus);
        const res = await aiApi.chat({
          provider,
          model: model || undefined,
          question: q,
          context: ctx,
          skillId,
        });
        setMessages((m) =>
          m.map((msg) =>
            msg.id === typingId
              ? {
                  ...msg,
                  text: res.text || "（AI 沒有回傳文字）",
                  meta: [
                    `${res.provider} · ${res.model}`,
                    res.mcp?.hasLiveData ? `MCP: ${res.mcp.summary || "已附即時資料"}` : "",
                  ].filter(Boolean).join(" · "),
                }
              : msg
          )
        );
      } catch (e) {
        const err = e instanceof Error ? e.message : String(e);
        setMessages((m) =>
          m.map((msg) =>
            msg.id === typingId ? { ...msg, text: `呼叫失敗：${err}`, meta: "錯誤" } : msg
          )
        );
      } finally {
        setBusy(false);
      }
    },
    [draft, busy, status, focus, collectContext, updateContextLabel, provider, model]
  );

  const openAI = useCallback(
    (opts?: OpenAIOpts) => {
      const f = opts?.focus ?? focus;
      if (opts?.focus) setFocus(opts.focus);
      setOpen(true);
      void refreshStatus();
      void updateContextLabel(f);
      if (opts?.question) {
        setDraft(opts.question);
        if (opts.send !== false) void sendMessage(opts.question, f);
      }
    },
    [focus, refreshStatus, updateContextLabel, sendMessage]
  );

  const value = useMemo(
    () => ({
      open,
      busy,
      messages,
      draft,
      setDraft,
      focus,
      contextLabel,
      status,
      provider,
      setProvider,
      model,
      setModel,
      openAI,
      closeAI: () => setOpen(false),
      sendMessage,
      clearChat: () =>
        setMessages([
          {
            id: `w-${Date.now()}`,
            role: "assistant",
            text: "對話已清除。還想問什麼？",
            meta: "導覽員",
          },
        ]),
      refreshStatus,
    }),
    [
      open,
      busy,
      messages,
      draft,
      focus,
      contextLabel,
      status,
      provider,
      model,
      openAI,
      sendMessage,
      refreshStatus,
    ]
  );

  useEffect(() => {
    void refreshStatus();
  }, [refreshStatus]);

  return <AIContext.Provider value={value}>{children}</AIContext.Provider>;
}

export function useAI() {
  const ctx = useContext(AIContext);
  if (!ctx) throw new Error("useAI must be used within AIProvider");
  return ctx;
}