/* global React, ReactDOM, Icon, Sidebar, Editor, DocumentPreview, HistoryPanel, SOPStore, SOPExport */
/* Main app */

const { useState, useEffect, useRef, useMemo, useCallback } = React;

/* Editable title strip shown above the live preview. */
function DocTitleBar({ doc, onChange }) {
  const [editing, setEditing] = useState(false);
  const [draft, setDraft] = useState(doc.title || "");
  const inputRef = useRef(null);

  useEffect(() => { if (!editing) setDraft(doc.title || ""); }, [doc.title, editing]);
  useEffect(() => {
    if (editing && inputRef.current) {
      inputRef.current.focus();
      inputRef.current.select();
    }
  }, [editing]);

  const commit = () => {
    const v = draft.trim();
    if (v && v !== doc.title) onChange({ ...doc, title: v, updatedAt: Date.now() });
    setEditing(false);
  };

  const stepCount = doc.phases?.reduce((n, p) => n + (p.steps?.length || 0), 0) || 0;

  return (
    <div className="doc-title-bar">
      <span className="preview__bar-dot" />
      {editing ? (
        <input
          ref={inputRef}
          className="doc-title-bar__input"
          value={draft}
          onChange={(e) => setDraft(e.target.value)}
          onBlur={commit}
          onKeyDown={(e) => {
            if (e.key === "Enter") commit();
            if (e.key === "Escape") { setDraft(doc.title || ""); setEditing(false); }
          }}
          placeholder="Título del SOP"
        />
      ) : (
        <button className="doc-title-bar__title" onClick={() => setEditing(true)} title="Editar título">
          {doc.title?.trim() || <em style={{ color: "var(--fg-3)" }}>Sin título</em>}
          <Icon name="edit" size={11} />
        </button>
      )}
      <span className="doc-title-bar__sep">·</span>
      <span className="doc-title-bar__meta">v{doc.version || "1.0"}</span>
      <span className="doc-title-bar__sep">·</span>
      <span className="doc-title-bar__meta">{stepCount} pasos</span>
    </div>
  );
}

function App() {
  // ----- mode (Simple = IA-first / Avanzado = editor manual) -----
  const [mode, setMode] = useState(() => {
    try { return localStorage.getItem("adslaw_sop_mode") || "simple"; } catch (e) { return "simple"; }
  });
  useEffect(() => { try { localStorage.setItem("adslaw_sop_mode", mode); } catch (e) {} }, [mode]);

  // ----- doc collection -----
  const [docs, setDocs] = useState(() => {
    const loaded = window.SOPStore.load();
    if (loaded.length > 0) return loaded;
    // bootstrap with one example doc so the user immediately sees what the
    // output looks like
    return [window.SOPStore.exampleDoc()];
  });
  const [activeId, setActiveId] = useState(() => {
    const stored = window.SOPStore.loadActiveId();
    return stored || null;
  });

  // ensure activeId is valid
  useEffect(() => {
    if (!docs.length) return;
    if (!activeId || !docs.find(d => d.id === activeId)) {
      setActiveId(docs[0].id);
    }
  }, [docs, activeId]);

  // persist on every change (debounced)
  useEffect(() => {
    const t = setTimeout(() => {
      window.SOPStore.save(docs);
      window.SOPStore.saveActiveId(activeId);
    }, 200);
    return () => clearTimeout(t);
  }, [docs, activeId]);

  const activeDoc = docs.find(d => d.id === activeId) || docs[0];

  // ----- historial: snapshot la versión PREVIA antes de aplicar un cambio -----
  // Estrategia: cuando updateActive se llama, guardamos en historial el doc
  // que estaba ANTES, etiquetado con el motivo del cambio si nos lo pasaron.
  // Esto da una línea de tiempo de "estados pasados" desde los que restaurar.
  const updateActive = (next, changeLabel) => {
    setDocs(currentDocs => {
      const prev = currentDocs.find(d => d.id === next.id);
      if (prev) {
        try { window.SOPStore.pushVersion(prev.id, prev, changeLabel || "Edición"); }
        catch (e) { /* historial es best-effort */ }
      }
      return currentDocs.map(d => d.id === next.id ? next : d);
    });
  };

  // Wrapper que el SimpleEditor/Editor usan: detectan a grandes rasgos qué tipo
  // de edición fue. Para edits inline (typing en un campo) lo dejamos como
  // "Edición" — el dedup del storage agrupa cambios contiguos por updatedAt.
  const updateActiveAuto = (next) => {
    // Detección heurística del label según el delta vs el doc actual.
    let label = "Edición";
    if (activeDoc) {
      const oldPhases = (activeDoc.phases || []).length;
      const newPhases = (next.phases || []).length;
      if (Math.abs(oldPhases - newPhases) > 0) label = newPhases > oldPhases ? "Fases añadidas" : "Fases eliminadas";
      else if ((activeDoc.title || "") !== (next.title || "")) label = "Título cambiado";
      else {
        const oldSteps = (activeDoc.phases || []).reduce((n, p) => n + (p.steps?.length || 0), 0);
        const newSteps = (next.phases || []).reduce((n, p) => n + (p.steps?.length || 0), 0);
        if (oldSteps !== newSteps) label = newSteps > oldSteps ? "Pasos añadidos" : "Pasos eliminados";
      }
    }
    updateActive(next, label);
  };

  const createNew = () => {
    const d = window.SOPStore.emptyDoc();
    setDocs(prev => [d, ...prev]);
    setActiveId(d.id);
  };

  const duplicate = () => {
    if (!activeDoc) return;
    const copy = { ...JSON.parse(JSON.stringify(activeDoc)), id: window.SOPStore.uid(), title: (activeDoc.title || "SOP") + " (copia)", createdAt: Date.now(), updatedAt: Date.now() };
    setDocs(prev => [copy, ...prev]);
    setActiveId(copy.id);
    showToast("Duplicado ✓");
  };

  const deleteDoc = (id) => {
    setDocs(prev => prev.filter(d => d.id !== id));
    if (id === activeId) setActiveId(null);
    // El historial se mantiene aunque el doc se borre: si después se restaura
    // el doc desde un export JSON con el mismo id, vuelve a tener historial.
  };

  // Restaurar una versión desde el HistoryPanel: reemplaza el doc actual con
  // el snapshot recuperado, agrega un updatedAt actual, y guarda la versión
  // que se estaba reemplazando para no perderla.
  const restoreVersion = (restored) => {
    if (!restored) return;
    const next = { ...restored, updatedAt: Date.now() };
    updateActive(next, "Versión restaurada");
  };

  const renameDoc = (id, newTitle) => {
    setDocs(prev => prev.map(d => d.id === id ? { ...d, title: newTitle, updatedAt: Date.now() } : d));
    showToast("Renombrado ✓");
  };

  // ----- toast -----
  const [toast, setToast] = useState(null);
  const showToast = (msg) => {
    setToast(msg);
    setTimeout(() => setToast(null), 2200);
  };

  // ----- history panel -----
  const [historyOpen, setHistoryOpen] = useState(false);

  // ----- provider toggle (Codex via suscripción ChatGPT / Ollama fallback) -----
  // Default = codex porque la calidad y la velocidad son mejores. Ollama queda
  // como fallback para cuando codex no esté disponible (token vencido, etc).
  // El provider activo se persiste en localStorage y se usa para todas las
  // llamadas a /api/complete (modos Simple y Avanzado).
  const [provider, setProvider] = useState(() => {
    try { return localStorage.getItem("adslaw_sop_provider") || "codex"; } catch (e) { return "codex"; }
  });
  useEffect(() => {
    try { localStorage.setItem("adslaw_sop_provider", provider); } catch (e) {}
    // Lo expone también en window para que claude-shim.js lo lea sin necesitar
    // tocar localStorage en cada request.
    window.__SOP_PROVIDER = provider;
  }, [provider]);
  // Catalogo de providers desde el backend (para saber cuál está disponible)
  const [providersCatalog, setProvidersCatalog] = useState([]);
  useEffect(() => {
    fetch("/api/agent/providers").then(r => r.json()).then(d => {
      const list = d.providers || [];
      // Re-ordenar: codex primero, ollama después. El backend devuelve en
      // orden de inserción; el toggle del header respeta este array.
      list.sort((a, b) => {
        if (a.id === "codex") return -1;
        if (b.id === "codex") return 1;
        return 0;
      });
      setProvidersCatalog(list);
      // Si el provider activo no está disponible, preferimos codex > ollama.
      const found = list.find(p => p.id === provider);
      if (!found || !found.available) {
        const codex = list.find(p => p.id === "codex" && p.available);
        const avail = codex || list.find(p => p.available);
        if (avail) setProvider(avail.id);
      }
    }).catch(() => {});
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, []);

  // ----- popup de confirmación al cambiar a Ollama (calidad/velocidad menor) -----
  const [providerSwitchModal, setProviderSwitchModal] = useState({ open: false, targetId: null });
  const onProviderClick = (p) => {
    if (!p.available || p.id === provider) return;
    // Si pasa de codex → ollama, pedir confirmación.
    if (provider === "codex" && p.id === "ollama") {
      setProviderSwitchModal({ open: true, targetId: p.id });
      return;
    }
    setProvider(p.id);
  };
  const confirmProviderSwitch = () => {
    const target = providerSwitchModal.targetId;
    setProviderSwitchModal({ open: false, targetId: null });
    if (target) setProvider(target);
  };
  const cancelProviderSwitch = () => setProviderSwitchModal({ open: false, targetId: null });

  // ----- export menu -----
  const [exportOpen, setExportOpen] = useState(false);
  const exportRef = useRef(null);
  useEffect(() => {
    if (!exportOpen) return;
    const onClick = (e) => {
      if (exportRef.current && !exportRef.current.contains(e.target)) setExportOpen(false);
    };
    document.addEventListener("mousedown", onClick);
    return () => document.removeEventListener("mousedown", onClick);
  }, [exportOpen]);

  const doExport = (fmt) => {
    setExportOpen(false);
    if (!activeDoc) return;
    if (fmt === "pdf") {
      // Slight delay so the menu closes before the print dialog
      setTimeout(() => window.SOPExport.exportPDF(), 100);
    } else if (fmt === "docx") {
      window.SOPExport.exportDOCX(activeDoc);
      showToast(".doc descargado ✓");
    } else if (fmt === "html") {
      window.SOPExport.exportHTML(activeDoc);
      showToast("HTML descargado ✓");
    } else if (fmt === "json") {
      window.SOPExport.exportJSON(activeDoc);
      showToast("JSON descargado ✓");
    } else if (fmt === "drive") {
      openDriveModal();
    }
  };

  // ----- subir a Drive -----
  // LAST_DRIVE_FOLDER se persiste en localStorage para no tener que volver a
  // pegar la URL cada vez que querés subir un SOP a la misma carpeta.
  const DRIVE_LAST_KEY = "sopcreator.drive.lastFolderUrl";
  const [driveModal, setDriveModal] = useState({ open: false, folderUrl: "", uploading: false, error: null, result: null });
  const openDriveModal = () => {
    setExportOpen(false);
    const last = localStorage.getItem(DRIVE_LAST_KEY) || "";
    setDriveModal({ open: true, folderUrl: last, uploading: false, error: null, result: null });
  };
  const closeDriveModal = () => setDriveModal(s => ({ ...s, open: false }));
  const submitDriveUpload = async () => {
    if (!activeDoc) return;
    const folderUrl = driveModal.folderUrl.trim();
    if (!folderUrl) { setDriveModal(s => ({ ...s, error: "Pegá la URL de la carpeta de Drive." })); return; }
    setDriveModal(s => ({ ...s, uploading: true, error: null, result: null }));
    try {
      // Reusamos buildDocxHTML para mandar el mismo HTML que el botón Word.
      // Drive lo convierte a Google Doc nativo via mimeType.
      const html = window.SOPExport.buildHTML(activeDoc);
      const filename = (activeDoc.title || "SOP sin título").slice(0, 100);
      const res = await fetch("/api/upload-to-drive", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({ filename, folder_url: folderUrl, html }),
      });
      const json = await res.json();
      if (!res.ok) throw new Error(json?.detail || `HTTP ${res.status}`);
      localStorage.setItem(DRIVE_LAST_KEY, folderUrl);
      setDriveModal(s => ({ ...s, uploading: false, result: json }));
      showToast("Subido a Drive ✓");
    } catch (e) {
      setDriveModal(s => ({ ...s, uploading: false, error: String(e.message || e) }));
    }
  };

  // ----- last update string -----
  // OJO: debe ir ANTES de cualquier early return para no violar el orden de
  // hooks de React. Si activeDoc es undefined (todos los SOPs borrados),
  // devolvemos string vacío.
  const lastUpdate = useMemo(() => {
    if (!activeDoc?.updatedAt) return "";
    const diff = (Date.now() - activeDoc.updatedAt) / 1000;
    if (diff < 5) return "ahora";
    if (diff < 60) return `hace ${Math.round(diff)} s`;
    if (diff < 3600) return `hace ${Math.round(diff / 60)} min`;
    return `hace ${Math.round(diff / 3600)} h`;
  }, [activeDoc?.updatedAt]);

  if (!activeDoc) {
    return (
      <div style={{ display: "flex", alignItems: "center", justifyContent: "center", height: "100vh", flexDirection: "column", gap: 16 }}>
        <p className="muted">No hay SOP activo.</p>
        <button className="btn btn--primary" onClick={createNew}><Icon name="plus" size={13} /> Crear primer SOP</button>
      </div>
    );
  }

  return (
    <div className="app">
      {/* ============ HEADER ============ */}
      <header className="app__header">
        <div className="brand">
          <img src="assets/mark-teal.png" alt="" className="brand__mark" />
          <div className="brand__divider" />
          <span className="brand__name">ads&amp;law</span>
          <span className="brand__dot">·</span>
          <span className="brand__product">SOP Creator</span>
        </div>

        <div className="mode-toggle" title="Cambiar modo de edición">
          <button className={`mode-toggle__btn ${mode === "simple" ? "mode-toggle__btn--active" : ""}`} onClick={() => setMode("simple")}>
            <Icon name="sparkles" size={12} /> Simple
          </button>
          <button className={`mode-toggle__btn ${mode === "advanced" ? "mode-toggle__btn--active" : ""}`} onClick={() => setMode("advanced")}>
            <Icon name="list" size={12} /> Avanzado
          </button>
        </div>

        {providersCatalog.length > 0 && (
          <div className="provider-toggle" title="Modelo de IA usado por Simple y Avanzado">
            {providersCatalog.map(p => (
              <button
                key={p.id}
                className={`provider-toggle__btn ${provider === p.id ? "provider-toggle__btn--active" : ""}`}
                onClick={() => onProviderClick(p)}
                disabled={!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 className="header__actions">
          <span style={{ fontFamily: "var(--font-mono)", fontSize: 11, color: "var(--fg-3)" }}>
            Guardado · {lastUpdate}
          </span>
          <button className="btn" onClick={() => setHistoryOpen(true)} title="Historial de versiones">
            <Icon name="layers" size={13} /> Historial
          </button>
          <button className="btn" onClick={duplicate} title="Duplicar SOP">
            <Icon name="copy" size={13} /> Duplicar
          </button>
          <div className="dropdown" ref={exportRef}>
            <button className="btn btn--primary" onClick={() => setExportOpen(o => !o)}>
              <Icon name="download" size={13} /> Exportar
              <Icon name="chevronDown" size={12} />
            </button>
            {exportOpen && (
              <div className="dropdown__menu">
                <button className="dropdown__item" onClick={() => doExport("pdf")}>
                  <Icon name="printer" size={15} /> Imprimir / Guardar como PDF
                  <span className="dropdown__item-sub">⌘P</span>
                </button>
                <button className="dropdown__item" onClick={() => doExport("docx")}>
                  <Icon name="fileText" size={15} /> .doc
                  <span className="dropdown__item-sub">Word · Google Docs</span>
                </button>
                <button className="dropdown__item" onClick={() => doExport("drive")}>
                  <Icon name="upload" size={15} /> Subir a Google Drive
                  <span className="dropdown__item-sub">Como Google Doc</span>
                </button>
                <button className="dropdown__item" onClick={() => doExport("html")}>
                  <Icon name="fileDown" size={15} /> HTML
                </button>
                <button className="dropdown__item" onClick={() => doExport("json")}>
                  <Icon name="layers" size={15} /> JSON
                  <span className="dropdown__item-sub">backup</span>
                </button>
              </div>
            )}
          </div>
        </div>
      </header>

      {/* ============ SIDEBAR ============ */}
      <Sidebar
        docs={docs}
        activeId={activeId}
        onSelect={setActiveId}
        onNew={createNew}
        onDelete={deleteDoc}
        onRename={renameDoc}
      />

      {/* ============ MAIN ============ */}
      <main className="app__main">
        {mode === "simple"
          ? <window.SimpleEditor doc={activeDoc} onChange={updateActiveAuto} onToast={showToast} />
          : <Editor doc={activeDoc} onChange={updateActiveAuto} onToast={showToast} />
        }
        <div className="preview">
          <div className="preview__inner">
            <DocTitleBar doc={activeDoc} onChange={updateActive} />
            <DocumentPreview doc={activeDoc} />
          </div>
        </div>
      </main>

      {toast && (
        <div className="toast">
          <Icon name="check" size={14} /> {toast}
        </div>
      )}

      {/* Panel de actividad de la IA — escucha los eventos del shim y muestra
          progreso en vivo cuando Simple o Avanzado llaman a window.claude.complete.
          El modo Agente tiene su propio activity log dentro de AgentMode. */}
      <window.AIActivity />

      {/* ============ MODAL: CAMBIAR A OLLAMA (degradación) ============ */}
      {providerSwitchModal.open && (
        <div className="modal-backdrop" onClick={(e) => { if (e.target === e.currentTarget) cancelProviderSwitch(); }}>
          <div className="modal-card" role="dialog" aria-modal="true" aria-labelledby="provider-switch-title">
            <header className="modal-header">
              <h2 className="modal-title" id="provider-switch-title">
                <Icon name="alert" size={16} /> Cambiar a Ollama
              </h2>
              <button className="modal-close" onClick={cancelProviderSwitch} aria-label="Cerrar">
                <Icon name="x" size={16} />
              </button>
            </header>
            <div className="modal-body">
              <p className="modal-help">
                Estás a punto de cambiar el modelo de IA de <strong>Codex</strong> a <strong>Ollama</strong>.
              </p>
              <p className="modal-help" style={{ marginTop: 8 }}>
                La calidad y velocidad de Ollama son <strong>ligeramente menores</strong>. Usalo solo cuando Codex no esté disponible (por ejemplo si el login venció).
              </p>
              <p className="modal-hint">
                Podés volver a Codex cuando quieras desde el mismo toggle del header.
              </p>
            </div>
            <footer className="modal-footer">
              <button className="btn" onClick={cancelProviderSwitch}>Cancelar</button>
              <button className="btn btn--primary" onClick={confirmProviderSwitch}>
                Cambiar a Ollama igualmente
              </button>
            </footer>
          </div>
        </div>
      )}

      {/* ============ MODAL: SUBIR A GOOGLE DRIVE ============ */}
      {driveModal.open && (
        <div className="modal-backdrop" onClick={(e) => { if (e.target === e.currentTarget) closeDriveModal(); }}>
          <div className="modal-card" role="dialog" aria-modal="true" aria-labelledby="drive-modal-title">
            <header className="modal-header">
              <h2 className="modal-title" id="drive-modal-title">
                <Icon name="upload" size={16} /> Subir a Google Drive
              </h2>
              <button className="modal-close" onClick={closeDriveModal} aria-label="Cerrar">
                <Icon name="x" size={16} />
              </button>
            </header>

            <div className="modal-body">
              {!driveModal.result && (
                <>
                  <p className="modal-help">
                    Pegá la URL de la carpeta de Drive donde querés subir <strong>{activeDoc?.title || "este SOP"}</strong>.
                    Se sube como <strong>Google Doc nativo</strong>, no como Word.
                  </p>
                  <label className="modal-label" htmlFor="drive-folder-input">
                    URL de la carpeta
                  </label>
                  <input
                    id="drive-folder-input"
                    className="modal-input"
                    type="url"
                    autoFocus
                    placeholder="https://drive.google.com/drive/folders/..."
                    value={driveModal.folderUrl}
                    onChange={(e) => setDriveModal(s => ({ ...s, folderUrl: e.target.value, error: null }))}
                    onKeyDown={(e) => { if (e.key === "Enter" && !driveModal.uploading) submitDriveUpload(); }}
                    disabled={driveModal.uploading}
                  />
                  <p className="modal-hint">
                    La cuenta <code>automatizaciones@adsandlaw.com</code> tiene que tener permiso de Editor en esa carpeta.
                  </p>
                  {driveModal.error && (
                    <div className="modal-error">
                      <Icon name="x" size={13} /> {driveModal.error}
                    </div>
                  )}
                </>
              )}

              {driveModal.result && (
                <div className="modal-success">
                  <div className="modal-success-icon"><Icon name="check" size={18} /></div>
                  <div className="modal-success-body">
                    <div className="modal-success-title">Subido a Drive ✓</div>
                    <div className="modal-success-name">{driveModal.result.name}</div>
                    <a className="modal-success-link" href={driveModal.result.url} target="_blank" rel="noopener noreferrer">
                      Abrir en Google Docs <Icon name="externalLink" size={11} />
                    </a>
                  </div>
                </div>
              )}
            </div>

            <footer className="modal-footer">
              {!driveModal.result ? (
                <>
                  <button className="btn" onClick={closeDriveModal} disabled={driveModal.uploading}>
                    Cancelar
                  </button>
                  <button
                    className="btn btn--primary"
                    onClick={submitDriveUpload}
                    disabled={!driveModal.folderUrl.trim() || driveModal.uploading}
                  >
                    {driveModal.uploading ? (
                      <><span className="modal-spinner" /> Subiendo…</>
                    ) : (
                      <><Icon name="upload" size={13} /> Subir</>
                    )}
                  </button>
                </>
              ) : (
                <>
                  <button className="btn" onClick={closeDriveModal}>Cerrar</button>
                  <button className="btn btn--primary" onClick={() => setDriveModal(s => ({ ...s, result: null }))}>
                    Subir otra vez
                  </button>
                </>
              )}
            </footer>
          </div>
        </div>
      )}


      <HistoryPanel
        docId={activeDoc?.id}
        open={historyOpen}
        onClose={() => setHistoryOpen(false)}
        onRestore={restoreVersion}
        onToast={showToast}
      />
    </div>
  );
}

ReactDOM.createRoot(document.getElementById("root")).render(<App />);
