/* global React, Icon, MicButton */
/* AgentMode — UX tipo Claude Code / Cursor:
   - El usuario escribe una instrucción
   - Backend corre un loop de agente con tool calling
   - Stream SSE de eventos tipados que renderizamos como activity log
   - Plan progress arriba (todos), filas de tool calls + bullets de prosa
   - Cuando el agente llama done, aplicamos el SOP final al doc activo */

const { useState: useStateAG, useRef: useRefAG, useEffect: useEffectAG, useMemo: useMemoAG } = React;

const TOOL_LABELS = {
  set_todos: { verb: "Actualizando plan", icon: "list" },
  update_sop: { verb: "Aplicando cambios al SOP", icon: "edit" },
  replace_sop: { verb: "Estructurando SOP completo", icon: "sparkles" },
  add_phase: { verb: "Agregando fase", icon: "plus" },
  update_step: { verb: "Editando paso", icon: "edit" },
  done: { verb: "Finalizando", icon: "check" },
};

function PlanProgress({ todos }) {
  if (!todos || !todos.length) return null;
  const completed = todos.filter(t => t.status === "completed").length;
  return (
    <div className="agent-plan">
      <div className="agent-plan-head">
        <Icon name="list" size={13} />
        <span className="agent-plan-title">Plan</span>
        <span className="agent-plan-counter">{completed}/{todos.length} done</span>
      </div>
      <ul className="agent-plan-list">
        {todos.map((t, i) => (
          <li key={i} className={`agent-plan-item agent-plan-item--${t.status}`}>
            <span className="agent-plan-bullet">
              {t.status === "completed" ? <Icon name="check" size={11} />
                : t.status === "in_progress" ? <span className="agent-plan-spinner" />
                : <span className="agent-plan-empty" />}
            </span>
            <span className="agent-plan-text">{t.text}</span>
          </li>
        ))}
      </ul>
    </div>
  );
}

function ActivityRow({ item }) {
  if (item.kind === "text") {
    return (
      <div className="agent-row agent-row--text">
        <span className="agent-row-dot" />
        <span className="agent-row-content">{item.text}</span>
      </div>
    );
  }
  if (item.kind === "tool") {
    const meta = TOOL_LABELS[item.name] || { verb: item.name, icon: "zap" };
    return (
      <div className={`agent-row agent-row--tool ${item.status === "pending" ? "agent-row--pending" : ""} ${item.isError ? "agent-row--err" : ""}`}>
        <span className="agent-row-icon">
          {item.status === "pending"
            ? <span className="agent-row-spinner" />
            : item.isError
              ? <Icon name="x" size={12} />
              : <Icon name={meta.icon} size={12} />}
        </span>
        <span className="agent-row-content">
          <span className="agent-row-verb">{meta.verb}</span>
          {item.summary && <span className="agent-row-summary"> · {item.summary}</span>}
        </span>
      </div>
    );
  }
  if (item.kind === "error") {
    return (
      <div className="agent-row agent-row--err">
        <span className="agent-row-icon"><Icon name="x" size={12} /></span>
        <span className="agent-row-content">Error: {item.message}</span>
      </div>
    );
  }
  if (item.kind === "done") {
    return (
      <div className="agent-row agent-row--done">
        <span className="agent-row-icon"><Icon name="check" size={13} /></span>
        <span className="agent-row-content">
          <strong>Listo.</strong> {item.summary}
        </span>
      </div>
    );
  }
  return null;
}

function summarizeToolArgs(name, args, result) {
  if (!args) return "";
  switch (name) {
    case "set_todos":
      return (args.todos || []).length + " items";
    case "replace_sop":
      return args.sop?.title ? `"${args.sop.title}"` : "";
    case "update_sop":
      return Object.keys(args.patch || {}).join(", ");
    case "add_phase":
      return `Fase ${args.num}: ${args.title || ""}`;
    case "update_step":
      return `${args.phase_num}.${args.step_num}`;
    case "done":
      return "";
    default:
      return "";
  }
}

function AgentMode({ doc, onChange, onToast }) {
  const [text, setText] = useStateAG("");
  const [running, setRunning] = useStateAG(false);
  const [todos, setTodos] = useStateAG([]);
  const [activity, setActivity] = useStateAG([]);  // [{kind:"text"|"tool"|"done"|"error", ...}]
  const [error, setError] = useStateAG("");
  const [provider, setProvider] = useStateAG(() => {
    try { return localStorage.getItem("adslaw_sop_agent_provider") || "ollama"; } catch (e) { return "ollama"; }
  });
  const [providers, setProviders] = useStateAG([]);  // catalogo desde el backend
  const taRef = useRefAG(null);
  const abortRef = useRefAG(null);
  const scrollRef = useRefAG(null);

  // Cargar catalogo de providers (sabemos cuál tiene auth válida)
  useEffectAG(() => {
    fetch("/api/agent/providers").then(r => r.json()).then(d => {
      setProviders(d.providers || []);
      // Si el provider guardado no está disponible, fallback a uno que sí
      const stored = provider;
      const list = d.providers || [];
      const found = list.find(p => p.id === stored);
      if (!found || !found.available) {
        const avail = list.find(p => p.available);
        if (avail) setProvider(avail.id);
      }
    }).catch(() => { /* sin catalog: usamos lo que sea */ });
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  useEffectAG(() => {
    try { localStorage.setItem("adslaw_sop_agent_provider", provider); } catch (e) {}
  }, [provider]);

  // Auto-scroll del activity log a medida que llegan eventos
  useEffectAG(() => {
    const el = scrollRef.current;
    if (el) el.scrollTop = el.scrollHeight;
  }, [activity.length, todos.length]);

  const pushActivity = (item) => setActivity(prev => [...prev, item]);
  const updateActivityById = (callId, patch) =>
    setActivity(prev => prev.map(it => (it.kind === "tool" && it.callId === callId) ? { ...it, ...patch } : it));

  const handleEvent = (event, data) => {
    if (event === "run_start") {
      setActivity([]);
      setTodos([]);
      setError("");
    } else if (event === "text_delta") {
      pushActivity({ kind: "text", text: data.text });
    } else if (event === "tool_start") {
      pushActivity({
        kind: "tool",
        callId: data.callId,
        name: data.name,
        status: "pending",
        summary: summarizeToolArgs(data.name, data.args, null),
        args: data.args,
      });
      // set_todos: refresh inmediato del plan (no esperamos al tool_end)
      if (data.name === "set_todos" && Array.isArray(data.args?.todos)) {
        setTodos(data.args.todos);
      }
    } else if (event === "tool_end") {
      updateActivityById(data.callId, {
        status: "done",
        isError: !!data.isError,
        result: data.result,
      });
      // Si el snapshot trae todos actualizados, los reflejamos (canónico desde server)
      if (data.stateSnapshot?.todos) setTodos(data.stateSnapshot.todos);
    } else if (event === "done") {
      pushActivity({ kind: "done", summary: data.summary });
      if (data.finalSop && onChange) {
        // Aplica el SOP final al doc activo preservando el id original
        const merged = {
          ...data.finalSop,
          id: doc?.id,
          createdAt: doc?.createdAt || Date.now(),
          updatedAt: Date.now(),
        };
        onChange(merged);
      }
      onToast && onToast("Agente terminó ✓");
      setRunning(false);
      setText("");
    } else if (event === "error") {
      pushActivity({ kind: "error", message: data.message });
      setError(data.message || "Error del agente");
      setRunning(false);
    }
  };

  const run = async () => {
    setError("");
    if (!text.trim()) { setError("Escribe qué querés que haga el agente."); return; }
    setRunning(true);
    setActivity([]);
    setTodos([]);

    const ctrl = new AbortController();
    abortRef.current = ctrl;

    try {
      const resp = await fetch("/api/agent/run", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
          user_message: text.trim(),
          current_sop: doc || null,
          provider,
        }),
        signal: ctrl.signal,
      });
      if (!resp.ok) {
        const t = await resp.text().catch(() => "");
        throw new Error(`Backend ${resp.status}: ${t.slice(0, 200)}`);
      }
      const reader = resp.body.getReader();
      const decoder = new TextDecoder("utf-8");
      let buf = "";

      // Parser SSE: separamos por `\n\n`, cada bloque tiene `event:` y `data:`
      while (true) {
        const { value, done } = await reader.read();
        if (done) break;
        buf += decoder.decode(value, { stream: true });
        let idx;
        while ((idx = buf.indexOf("\n\n")) >= 0) {
          const chunk = buf.slice(0, idx);
          buf = buf.slice(idx + 2);
          if (!chunk.trim()) continue;
          let evName = "message";
          let evData = "";
          for (const line of chunk.split("\n")) {
            if (line.startsWith("event:")) evName = line.slice(6).trim();
            else if (line.startsWith("data:")) evData += line.slice(5).trim();
          }
          if (!evData) continue;
          let parsed;
          try { parsed = JSON.parse(evData); } catch { parsed = { raw: evData }; }
          handleEvent(evName, parsed);
        }
      }
    } catch (e) {
      if (e.name !== "AbortError") {
        setError(e.message || "Error de conexión");
        pushActivity({ kind: "error", message: e.message || "Conexión interrumpida" });
      }
      setRunning(false);
    }
  };

  const stop = () => {
    if (abortRef.current) abortRef.current.abort();
    setRunning(false);
    pushActivity({ kind: "error", message: "Run cancelado por el usuario." });
  };

  const onVoice = (t) => {
    setText(prev => {
      const sep = prev && !/\s$/.test(prev) ? " " : "";
      return (prev + sep + t).trim() + " ";
    });
  };

  return (
    <div className="agent-mode">
      <div className="agent-mode__inner">
        <div className="agent-mode__head">
          <div className="agent-mode__head-row">
            <h2 className="agent-mode__title">
              <Icon name="zap" size={18} /> Agente
            </h2>
            {providers.length > 0 && (
              <div className="agent-provider-toggle" title="Modelo y provider del agente">
                {providers.map(p => (
                  <button
                    key={p.id}
                    className={`agent-provider-btn ${provider === p.id ? "agent-provider-btn--active" : ""}`}
                    onClick={() => setProvider(p.id)}
                    disabled={running || !p.available}
                    title={p.available ? `${p.label} · ${p.model}` : `${p.label} · no configurado`}
                  >
                    {p.id === "codex" ? <Icon name="sparkles" size={11} /> : <Icon name="zap" size={11} />}
                    {p.label.split(" ")[0]}
                  </button>
                ))}
              </div>
            )}
          </div>
          <p className="agent-mode__sub">
            Decile en lenguaje natural qué querés hacer con este SOP. El agente arma un plan, ejecuta paso a paso y te muestra cada acción en vivo.
          </p>
        </div>

        {/* Activity log + plan (solo cuando hay algo) */}
        {(running || todos.length > 0 || activity.length > 0) && (
          <div className="agent-stream" ref={scrollRef}>
            {todos.length > 0 && <PlanProgress todos={todos} />}
            {activity.length > 0 && (
              <div className="agent-activity">
                <div className="agent-activity-head">
                  <Icon name="layers" size={12} />
                  <span>Activity ({activity.filter(a => a.kind === "tool").length} steps)</span>
                </div>
                {activity.map((item, i) => <ActivityRow key={i} item={item} />)}
                {running && (
                  <div className="agent-row agent-row--thinking">
                    <span className="agent-row-spinner" />
                    <span className="agent-row-content">Pensando…</span>
                  </div>
                )}
              </div>
            )}
          </div>
        )}

        {/* Input */}
        <div className="agent-input">
          <textarea
            ref={taRef}
            className="agent-input__ta"
            value={text}
            onChange={(e) => setText(e.target.value)}
            placeholder={
              doc?.title
                ? "Ej: 'Agregá una fase 4 de seguimiento post-launch con 2 pasos' o 'Cambiá la fase 2 para incluir verificación de tracking'"
                : "Ej: 'Crea un SOP para hacer el reporte mensual de un cliente. Quiero 4 fases: preparación, recolección, análisis y envío'"
            }
            disabled={running}
            rows={3}
          />
          <div className="agent-input__toolbar">
            <MicButton onTranscript={onVoice} lang="es-ES" size={36} />
            <span style={{ flex: 1 }} />
            {running ? (
              <button className="btn btn--danger" onClick={stop}>
                <Icon name="x" size={13} /> Cancelar
              </button>
            ) : (
              <button className="btn btn--primary" onClick={run} disabled={!text.trim()}>
                <Icon name="zap" size={13} /> Ejecutar agente
              </button>
            )}
          </div>
          {error && <div className="agent-input__err"><Icon name="x" size={12} /> {error}</div>}
        </div>

        {!running && activity.length === 0 && (
          <div className="agent-tips">
            <h3 className="agent-tips__title">Cómo funciona</h3>
            <ul className="agent-tips__list">
              <li>El agente primero arma un <strong>plan</strong> con todos visibles.</li>
              <li>Antes de cada acción te dice qué va a hacer.</li>
              <li>Ejecuta tools (estructurar, editar, agregar fase, etc.) y vos las ves en vivo.</li>
              <li>Al terminar aplica los cambios al SOP de la derecha.</li>
            </ul>
          </div>
        )}
      </div>
    </div>
  );
}

window.AgentMode = AgentMode;
