

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "accent": "#2563eb",
  "density": "regular",
  "radius": 12,
  "font": "Manrope",
  "dark": true
}/*EDITMODE-END*/;

const FONT_OPTIONS = [
  { id: "Manrope", label: "Manrope" },
  { id: "Plus Jakarta Sans", label: "Jakarta" },
  { id: "DM Sans", label: "DM Sans" },
  { id: "IBM Plex Sans", label: "IBM Plex" },
];

const ACCENT_OPTIONS = ["#2563eb", "#7c3aed", "#0ea5e9", "#10b981", "#f97316", "#e11d48"];

function App() {
  const [tweaks, setTweak] = useTweaks(TWEAK_DEFAULTS);
  const [view, setView]    = React.useState("tablero");
  const [tickets, setTickets]   = React.useState([]);
  const [archived, setArchived] = React.useState([]);
  const [projects, setProjects] = React.useState([]);
  const [openTicketId, setOpenTicketId] = React.useState(null);
  const [toasts, setToasts] = React.useState([]);
  const [loading, setLoading] = React.useState(true);
  const [authed, setAuthed] = React.useState(false);
  const [showSettingsModal, setShowSettingsModal] = React.useState(false);

  // Deep-link: si la URL trae ?ticket=TK-XXXX, recordamos el código
  // y abrimos el ticket apenas terminen de cargar.
  const deepLinkRef = React.useRef(
    new URLSearchParams(window.location.search).get("ticket")
  );

  // Tema + accent + densidad
  React.useEffect(() => {
    const root = document.documentElement;
    root.setAttribute("data-theme", tweaks.dark ? "dark" : "light");
    root.style.setProperty("--accent", tweaks.accent);
    root.style.setProperty("--radius", tweaks.radius + "px");
    root.style.setProperty("--radius-sm", Math.max(4, tweaks.radius - 4) + "px");
    root.style.setProperty("--radius-lg", (tweaks.radius + 4) + "px");
    const padY = { compact: 8, regular: 14, comfy: 20 }[tweaks.density] || 14;
    const padX = { compact: 10, regular: 16, comfy: 22 }[tweaks.density] || 16;
    const gap  = { compact: 10, regular: 16, comfy: 22 }[tweaks.density] || 16;
    root.style.setProperty("--pad-y", padY + "px");
    root.style.setProperty("--pad-x", padX + "px");
    root.style.setProperty("--gap", gap + "px");
    root.style.setProperty("--font-sans", `"${tweaks.font}", ui-sans-serif, system-ui, -apple-system, sans-serif`);
  }, [tweaks]);

  const pushToast = React.useCallback((msg, kind = "success") => {
    const id = Math.random().toString(36).slice(2, 9);
    setToasts(ts => [...ts, { id, msg, kind }]);
    setTimeout(() => setToasts(ts => ts.filter(t => t.id !== id)), 4000);
  }, []);
  const reportError = React.useCallback((e, fallback = "Error de servidor") => {
    pushToast((e && e.message) || fallback, "warn");
  }, [pushToast]);

  const reload = React.useCallback(async () => {
    try {
      const [active, archivedRows, projectRows] = await Promise.all([
        api.listActive(),
        api.listArchived(),
        api.listProjects(),
      ]);
      setTickets(active);
      setArchived(archivedRows);
      setProjects(projectRows);

      // Deep-link: abrir ticket recibido por ?ticket=TK-XXXX (una sola vez)
      const code = deepLinkRef.current;
      if (code) {
        deepLinkRef.current = null;
        const found = active.find(t => t.id === code) || archivedRows.find(t => t.id === code);
        if (found) {
          setOpenTicketId(found.id);
          setView(archivedRows.some(t => t.id === code) ? "archive" : "tablero");
        } else {
          pushToast(`Ticket ${code} no encontrado`, "warn");
        }
        // Limpia el query string sin recargar la página
        const url = new URL(window.location.href);
        url.searchParams.delete("ticket");
        window.history.replaceState({}, "", url.toString());
      }
    } catch (e) {
      reportError(e, "No se pudo cargar la información");
    } finally {
      setLoading(false);
    }
  }, [reportError, pushToast]);

  React.useEffect(() => {
    let alive = true;
    // Verifica sesión ANTES de renderizar el panel. Si no hay sesión,
    // jsonRequest devuelve undefined (tras un 401) y redirige a login.html;
    // así el panel nunca llega a mostrarse sin autenticación.
    api.me()
      .then((data) => {
        if (!data) return;            // 401 → ya está redirigiendo a login
        if (alive) { setAuthed(true); reload(); }
      })
      .catch(() => { /* jsonRequest ya redirige al login en 401 */ });
    return () => { alive = false; };
  }, [reload]);

  const handleLogout = async () => {
    try { await api.logout(); } catch (_) {}
    location.replace("login.html");
  };

  const openTicket = tickets.find(t => t.id === openTicketId)
                  || archived.find(t => t.id === openTicketId)
                  || null;
  const isOpenArchived = openTicket && archived.some(t => t.id === openTicket.id);

  const handleMove = async (frontTicketId, newStatus) => {
    const t = tickets.find(x => x.id === frontTicketId) || archived.find(x => x.id === frontTicketId);
    if (!t) return;
    try {
      const updated = await api.changeStatus(t._dbId, newStatus);

      if (newStatus === "finalizado") {
        setTickets(ts => ts.filter(x => x.id !== frontTicketId));
        setArchived(a => [updated, ...a.filter(x => x.id !== frontTicketId)]);
      } else {
        setArchived(a => a.filter(x => x.id !== frontTicketId));
        setTickets(ts => {
          const without = ts.filter(x => x.id !== frontTicketId);
          return [updated, ...without];
        });
      }

      // El backend envía el WhatsApp al cliente automáticamente.
      pushToast(
        `Ticket ${frontTicketId}: ${STATUS_LABEL[newStatus]} · WhatsApp enviado al cliente`,
        newStatus === "finalizado" ? "success" : "info"
      );
    } catch (e) { reportError(e, "No se pudo cambiar el estado"); }
  };

  const handleRestore = (frontTicketId) => handleMove(frontTicketId, "pendiente");

  const handleDelete = async (frontTicketId) => {
    const t = tickets.find(x => x.id === frontTicketId) || archived.find(x => x.id === frontTicketId);
    if (!t) return;
    try {
      await api.deleteTicket(t._dbId);
      setTickets(ts => ts.filter(x => x.id !== frontTicketId));
      setArchived(a => a.filter(x => x.id !== frontTicketId));
      setOpenTicketId(null);
      pushToast(`Ticket ${frontTicketId} eliminado`, "warn");
    } catch (e) { reportError(e, "No se pudo eliminar"); }
  };

  const handleChangeStatus = (id, status) => {
    handleMove(id, status);
    if (status === "finalizado") setOpenTicketId(null);
  };

  const handleCreateProject = async (nombre, groupId) => {
    try {
      const created = await api.createProject(nombre, groupId);
      setProjects(ps => [...ps, created]
        .sort((a, b) => a.nombre_proyecto.localeCompare(b.nombre_proyecto)));
      pushToast(`Proyecto "${created.nombre_proyecto}" creado`, "success");
      return created;
    } catch (e) {
      reportError(e, "No se pudo crear el proyecto");
      throw e;
    }
  };

  const handleUpdateProject = async (id, data) => {
    try {
      const updated = await api.updateProject(id, data);
      setProjects(ps => ps.map(p => p.id === id ? updated : p)
        .sort((a, b) => a.nombre_proyecto.localeCompare(b.nombre_proyecto)));
      pushToast(`Proyecto "${updated.nombre_proyecto}" actualizado`, "success");
      return updated;
    } catch (e) {
      reportError(e, "No se pudo actualizar el proyecto");
      throw e;
    }
  };

  const handleUpdateProjectGroup = async (id, groupId) => {
    try {
      const saved = await api.updateProjectGroup(id, groupId);
      setProjects(ps => ps.map(p => p.id === id ? { ...p, whatsapp_group_id: saved } : p));
      pushToast(saved ? "Grupo de WhatsApp actualizado" : "Grupo de WhatsApp eliminado", "success");
      return saved;
    } catch (e) {
      reportError(e, "No se pudo actualizar el grupo");
      throw e;
    }
  };

  const handleDeleteProject = async (id) => {
    try {
      await api.deleteProject(id);
      setProjects(ps => ps.filter(p => p.id !== id));
      pushToast("Proyecto eliminado", "warn");
    } catch (e) {
      reportError(e, "No se pudo eliminar el proyecto");
      throw e;
    }
  };

  const counts = {
    inbox:    tickets.length,
    tablero:  tickets.length,
    archive:  archived.length,
    proyectos: projects.length,
  };

  const viewLabels = {
    inbox:     { title: "Bandeja de entrada", sub: "Todos los tickets recibidos" },
    tablero:   { title: "Tablero de tickets", sub: "Gestión de tickets activos" },
    archive:   { title: "Archivo",            sub: "Tickets finalizados" },
    proyectos: { title: "Proyectos",          sub: "Catálogo visible para el cliente" },
  };

  // Gate de autenticación: hasta que `api.me()` confirme sesión, no se
  // renderiza el panel. Si no hay sesión, ya se está redirigiendo a login.html.
  if (!authed) {
    return (
      <div style={{
        minHeight: "100vh", display: "grid", placeItems: "center",
        color: "var(--ink-2)", fontSize: 14,
      }}>
        Verificando sesión…
      </div>
    );
  }

  return (
    <div className="app">
      <Sidebar view={view} setView={setView} counts={counts} />
      <div className="main">
        <header className="header">
          <div className="header-brand">
            <div className="hb-mark">
              <img src={ASSET_BASE + "/logo-cubelab.jpeg"} alt="CUBE LAB" />
            </div>
            <div className="hb-text">
              <b>CUBE LAB</b>
              <span>ticket</span>
            </div>
          </div>
          <h1>{viewLabels[view].title}</h1>
          <span className="header-sub">· {viewLabels[view].sub}</span>
          <div className="header-right">
            <button className="btn btn-sm" onClick={reload} title="Recargar datos" aria-label="Refrescar">
              <Icon name="rotate" style={{ width: 14, height: 14 }} />
              <span className="btn-label">Refrescar</span>
            </button>
            <button
              className="btn btn-sm"
              onClick={() => setShowSettingsModal(true)}
              title="Configuración"
              aria-label="Configuración"
            >
              <Icon name="bell" style={{ width: 14, height: 14 }} />
              <span className="btn-label">Config</span>
            </button>
            <button
              className="theme-toggle"
              onClick={() => setTweak("dark", !tweaks.dark)}
              aria-label={tweaks.dark ? "Cambiar a modo claro" : "Cambiar a modo oscuro"}
              title={tweaks.dark ? "Modo claro" : "Modo oscuro"}
            >
              <Icon name={tweaks.dark ? "sun" : "moon"} style={{ width: 16, height: 16 }} />
            </button>
            <button
              className="btn btn-sm btn-danger"
              onClick={handleLogout}
              title="Cerrar sesión"
              aria-label="Cerrar sesión"
            >
              <Icon name="logout" style={{ width: 15, height: 15 }} />
              <span className="btn-label">Salir</span>
            </button>
          </div>
        </header>

        {loading && (
          <div style={{ padding: 24, color: "var(--ink-2)", fontSize: 13 }}>
            Cargando datos del servidor…
          </div>
        )}

        {!loading && view === "inbox" && (
          <InboxView
            tickets={tickets}
            onOpenTicket={setOpenTicketId}
          />
        )}
        {!loading && view === "tablero" && (
          <KanbanView
            tickets={tickets}
            onOpenTicket={setOpenTicketId}
            onMove={handleMove}
            onCreate={null}
          />
        )}
        {!loading && view === "archive" && (
          <ArchiveView
            archived={archived}
            onOpenTicket={setOpenTicketId}
            onRestore={handleRestore}
            onDelete={handleDelete}
          />
        )}
        {!loading && view === "proyectos" && (
          <ProjectsView
            projects={projects}
            onCreate={handleCreateProject}
            onUpdate={handleUpdateProject}
            onUpdateGroup={handleUpdateProjectGroup}
            onDelete={handleDeleteProject}
          />
        )}
      </div>

      {openTicket && (
        <TicketModal
          ticket={openTicket}
          isArchived={isOpenArchived}
          onClose={() => setOpenTicketId(null)}
          onChangeStatus={handleChangeStatus}
          onDelete={handleDelete}
          onRestore={handleRestore}
        />
      )}

      {showSettingsModal && (
        <SettingsModal
          onClose={() => setShowSettingsModal(false)}
          onSuccess={(msg) => pushToast(msg, "success")}
          onError={(err) => reportError(err, "No se pudo guardar la configuración")}
        />
      )}

      <div className="toast-wrap">
        {toasts.map(t => (
          <div key={t.id} className={"toast t-" + t.kind}>
            <span className="toast-ic">
              <Icon
                name={t.kind === "success" ? "check" : t.kind === "warn" ? "alert" : "bell"}
                style={{ width: 12, height: 12 }}
              />
            </span>
            {t.msg}
          </div>
        ))}
      </div>

    </div>
  );
}

function Sidebar({ view, setView, counts }) {
  const items = [
    { id: "inbox",     icon: "inbox",   label: "Bandeja",  count: counts.inbox },
    { id: "tablero",   icon: "board",   label: "Tablero",  count: counts.tablero },
    { id: "archive",   icon: "archive", label: "Archivo",  count: counts.archive },
    { id: "proyectos", icon: "folder",  label: "Proyectos", count: counts.proyectos },
  ];
  return (
    <aside className="sidebar">
      <div className="brand">
        <div className="brand-mark">
          <img src={ASSET_BASE + "/logo-cubelab.jpeg"} alt="CUBE LAB" />
        </div>
        <div className="brand-name">
          <b>CUBE LAB</b>
          <span>ticket</span>
        </div>
      </div>
      <div className="nav-section">Navegación</div>
      {items.map(it => (
        <div
          key={it.id}
          className="nav-item"
          aria-current={view === it.id ? "page" : undefined}
          onClick={() => setView(it.id)}
          role="button"
          tabIndex={0}
          onKeyDown={e => { if (e.key === "Enter") setView(it.id); }}
        >
          <Icon name={it.icon} className="nav-icon" />
          {it.label}
          {it.count != null && <span className="nav-count">{it.count}</span>}
        </div>
      ))}
      <div className="sidebar-foot">
        <div style={{
          background: "var(--bg-3)", border: "1px solid var(--border)",
          padding: "12px", borderRadius: "10px", fontSize: 12,
          color: "var(--ink-2)", lineHeight: 1.45,
        }}>
          <div style={{ display: "flex", alignItems: "center", gap: 8, marginBottom: 6, color: "var(--ink-1)", fontWeight: 600 }}>
            <Icon name="whatsapp" style={{ width: 14, height: 14, color: "var(--done)" }} />
            Notificaciones por WhatsApp
          </div>
          Al cambiar el estado de un ticket se abre WhatsApp con el mensaje para el cliente.
        </div>
      </div>
    </aside>
  );
}

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