import { useEffect, useState, useRef, useCallback } from "react";
import { useKeyboard } from "@opentui/react";
import { listTools, callTool, MCPTool } from "../lib/mcp-api";
import { theme } from "../lib/theme";

type View = "list" | "schema" | "result" | "error";

export default function MCP() {
  const [tools, setTools] = useState<MCPTool[]>([]);
  const [cursor, setCursor] = useState(0);
  const [view, setView] = useState<View>("list");
  const [selected, setSelected] = useState<MCPTool | null>(null);
  const [args, setArgs] = useState("");
  const [result, setResult] = useState("");
  const [error, setError] = useState("");
  const [loading, setLoading] = useState(false);
  const [filter, setFilter] = useState("");
  const [editingArg, setEditingArg] = useState(false);
  const [argInput, setArgInput] = useState("{}");
  const [resultLoading, setResultLoading] = useState(false);
  const fetchRef = useRef(false);

  useEffect(() => {
    if (fetchRef.current) return;
    fetchRef.current = true;
    setLoading(true);
    listTools()
      .then((t) => { setTools(t); setLoading(false); })
      .catch((e) => { setError(e.message); setLoading(false); });
  }, []);

  const filtered = filter
    ? tools.filter((t) => t.name.toLowerCase().includes(filter.toLowerCase()))
    : tools;

  useKeyboard((evt: any) => {
    if (view === "result" || view === "error") {
      if (evt.name === "escape") { setView("list"); return; }
      return;
    }
    if (view === "schema") {
      if (evt.name === "escape") { setView("list"); return; }
      if (evt.key === "c") { setView("list"); return; }
      return;
    }
    if (editingArg) {
      if (evt.name === "escape") { setEditingArg(false); return; }
      if (evt.name === "enter") {
        try { JSON.parse(argInput); setArgs(argInput); setEditingArg(false); } catch {}
        return;
      }
      if (evt.key === "Backspace") { setArgInput((s) => s.slice(0, -1)); return; }
      if (evt.key && evt.key.length === 1 && !evt.ctrl) { setArgInput((s) => s + evt.key); return; }
      return;
    }
    if (view === "list") {
      if (evt.name === "up" || evt.key === "k") { setCursor((p) => Math.max(0, p - 1)); return; }
      if (evt.name === "down" || evt.key === "j") { setCursor((p) => Math.min(filtered.length - 1, p + 1)); return; }
      if (evt.name === "enter") {
        const tool = filtered[cursor];
        if (tool) {
          setSelected(tool);
          setView("schema");
          setArgs("");
          setResult("");
          setError("");
          setArgInput(JSON.stringify(
            tool.input_schema?.properties
              ? Object.fromEntries(
                  Object.entries(tool.input_schema.properties)
                    .filter(([_, v]: [string, any]) => tool.input_schema?.required?.includes(v))
                    .map(([k, v]: [string, any]) => [k, v.type === "string" ? "" : v.type === "number" ? 0 : v.type === "boolean" ? false : ""])
                )
              : {}, null, 2
          ));
        }
        return;
      }
      return;
    }
  }, [view, filtered.length, cursor, editingArg, argInput]);

  const doCall = useCallback(async () => {
    if (!selected) return;
    setResultLoading(true);
    setError("");
    setResult("");
    try {
      const parsed = JSON.parse(args || argInput || "{}");
      const res = await callTool(selected.name, parsed);
      setResult(res || "(no output)");
      setView("result");
    } catch (e: any) {
      setError(e?.message || String(e));
      setView("error");
    } finally {
      setResultLoading(false);
    }
  }, [selected, args, argInput]);

  useKeyboard((evt: any) => {
    if (view === "schema" && selected) {
      if (evt.name === "enter") { doCall(); return; }
      if (evt.key === "s") { setView("list"); return; }
      if (evt.key && evt.key.length === 1 && !evt.ctrl && !evt.name) {
        setArgInput((s) => s + evt.key);
        return;
      }
    }
  }, [view, selected, doCall]);

  return (
    <box flexDirection="column" flexGrow={1} padding={0}>
      <box height={1} paddingX={1}>
        <text bold fg={theme.accent}>Zo MCP</text>
        <text fg={theme.fgMuted}>  {tools.length} tools  </text>
        <text fg={theme.fgMuted} dim>[↑/↓] navigate  [Enter] select  [s] schema  [c] call  [r] result  [Esc] back</text>
      </box>

      {view === "list" && (
        <box flexGrow={1} flexDirection="row">
          <box flexDirection="column" width={40} borderColor={theme.border} borderStyle="single">
            <box height={1} paddingX={1}>
              <text fg={theme.fgMuted} dim>Tool</text>
              <text fg={theme.fgMuted} dim right>Parameters</text>
            </box>
            {loading && <text fg={theme.fgDim} paddingX={1}>Loading...</text>}
            {error && <text fg={theme.error} paddingX={1}>{error}</text>}
            {filtered.slice(0, 100).map((tool, i) => (
              <box key={tool.name} height={1} paddingX={1} bg={i === cursor ? theme.accent : undefined}>
                <text fg={i === cursor ? theme.bg : theme.fg} bold={i === cursor} wrap="ellipsis">
                  {tool.name}
                </text>
                <text right fg={i === cursor ? theme.bg : theme.fgDim} dim>
                  {tool.input_schema?.required?.length
                    ? `${tool.input_schema.required.length} req`
                    : tool.input_schema?.properties
                      ? `${Object.keys(tool.input_schema.properties).length} params`
                      : "—"}
                </text>
              </box>
            ))}
          </box>

          <box flexDirection="column" flexGrow={1} borderColor={theme.border} borderStyle="single">
            {selected ? (
              <>
                <box height={1} paddingX={1}>
                  <text bold fg={theme.accent}>{selected.name}</text>
                </box>
                <box flexGrow={1} paddingX={1} flexDirection="column">
                  <text fg={theme.fgDim} dim>{selected.description || "—"}</text>
                  <box height={1} />
                  <text fg={theme.fgMuted} dim>Parameters:</text>
                  {selected.input_schema?.properties
                    ? Object.entries(selected.input_schema.properties).map(([name, prop]: [string, any]) => (
                        <text key={name} fg={theme.fg}>
                          <text fg={theme.accent}>  {name}</text>
                          <text fg={theme.fgDim} dim>  {prop.type}</text>
                          {selected.input_schema?.required?.includes(name) && <text fg={theme.error}> *</text>}
                        </text>
                      ))
                    : <text fg={theme.fgMuted} dim>  (none)</text>}
                  <box height={1} />
                  <text fg={theme.fgMuted} dim>[Enter] call  [s] schema details  [c] edit args & call</text>
                </box>
              </>
            ) : (
              <text fg={theme.fgMuted} dim paddingX={1}>Select a tool</text>
            )}
          </box>
        </box>
      )}

      {view === "schema" && selected && (
        <box flexDirection="column" flexGrow={1} paddingX={1}>
          <text bold fg={theme.accent}>{selected.name}</text>
          <text fg={theme.fgDim} dim>{selected.description || "—"}</text>
          <box height={1} />
          <text fg={theme.fgMuted} dim>Input Schema:</text>
          <text fg={theme.fg}>{JSON.stringify(selected.input_schema, null, 2)}</text>
          <box height={1} />
          <text fg={theme.fgMuted} dim>Arguments (edit JSON, then press Enter to call):</text>
          <text fg={theme.fg}>{argInput}</text>
          <box height={1} />
          {resultLoading && <text fg={theme.fgDim}>Calling...</text>}
          {result && (
            <box flexDirection="column" flexGrow={1}>
              <text bold fg={theme.success}>Result:</text>
              <text fg={theme.fg}>{result.slice(0, 2000)}</text>
              {result.length > 2000 && <text fg={theme.fgDim}>... ({result.length - 2000} more chars)</text>}
            </box>
          )}
          {error && <text fg={theme.error}>{error}</text>}
          <text fg={theme.fgDim} dim>[Esc] back  ·  [Enter] call with args above  ·  type to edit args</text>
        </box>
      )}

      {(view === "result" || view === "error") && (
        <box flexDirection="column" flexGrow={1} paddingX={1}>
          <text bold fg={view === "result" ? theme.success : theme.error}>
            {view === "result" ? "Result" : "Error"}
          </text>
          <text fg={theme.fg}>{result || error}</text>
          <text fg={theme.fgDim} dim>[Esc] back</text>
        </box>
      )}
    </box>
  );
}