// App.jsx

const NAV = [
  { id: "dashboard",  label: "Visão geral",  icon: "Home",     kbd: "G" },
  { id: "diarios",    label: "Diários",      icon: "Book",     kbd: "D" },
  { id: "cronograma", label: "Cronograma",   icon: "Calendar", kbd: "C" },
  { id: "progresso",  label: "Progresso",    icon: "Chart",    kbd: "P" },
  { id: "financeiro", label: "Financeiro",   icon: "Wallet",   kbd: "F" },
  { id: "notas",      label: "Notas fiscais",icon: "Receipt",  kbd: "N" },
  { id: "cameras",    label: "Câmeras",      icon: "Cam",      kbd: "L" },
  { id: "documentos", label: "Documentos",   icon: "Doc",      kbd: "A" },
];

const NAV_LABELS = Object.fromEntries(NAV.map(n => [n.id, n.label]));

// Módulo liberado? PORTAL_PERMISSOES vem do backend (default: tudo true).
// Ids do NAV batem 1:1 com as chaves de permissão.
function isModuleEnabled(id) {
  const perms = window.PORTAL_PERMISSOES || {};
  return perms[id] !== false;
}
function enabledNav() {
  return NAV.filter((n) => isModuleEnabled(n.id));
}

const PAGES = {
  dashboard: (p) => <DashboardPage {...p} />,
  diarios:   () => <DiariosPage />,
  cronograma:() => <CronogramaPage />,
  progresso: () => <ProgressoPage />,
  financeiro:() => <FinanceiroPage />,
  notas:     () => <NotasFiscaisPage />,
  cameras:   () => <CamerasPage />,
  documentos:() => <DocumentosPage />,
};

function Sidebar({ active, onNav, onLogout }) {
  const user = window.PORTAL_USER || {};
  // Mostra a identidade de QUEM está logado (a conta ClientUser), não o síndico
  // cadastrado na obra — a conta pode ser de outra pessoa (ex: gestor, conselho).
  // Fallback: nome do síndico da obra, depois email.
  const displayName = user.nome || PROJECT.sindico || user.email || "Cliente";
  const displayRole = user.cargo || "Sindico";
  const initials = displayName
    .split(/\s+/).filter(Boolean).slice(0, 2).map((p) => p[0]?.toUpperCase()).join("") || "C";
  // Indicator pill — slides between active items
  const navRef = React.useRef(null);
  const [indicator, setIndicator] = React.useState({ top: 0, height: 0, visible: false });

  React.useLayoutEffect(() => {
    const el = navRef.current?.querySelector(`[data-nav="${active}"]`);
    if (!el || !navRef.current) return;
    const parentRect = navRef.current.getBoundingClientRect();
    const rect = el.getBoundingClientRect();
    setIndicator({
      top: rect.top - parentRect.top,
      height: rect.height,
      visible: true,
    });
  }, [active]);

  return (
    <aside className="sidebar">
      <div className="brand">
        <div className="brand-mark">N</div>
        <div>
          <div className="brand-name">Núcleo</div>
          <div className="brand-sub">PORTAL · CLIENTE</div>
        </div>
      </div>

      <div style={{ padding: "6px 8px 10px" }}>
        <div style={{ fontSize: 11.5, color: "#3A3A3A", fontWeight: 500, marginBottom: 2 }}>{PROJECT.name || "Sua obra"}</div>
        <div className="mono" style={{ fontSize: 10.5, color: "#999" }}>{PROJECT.code || "—"}</div>
        <div className="bar thin" style={{ marginTop: 10 }}>
          <span style={{ width: Math.round((PROJECT.progress || 0) * 100) + "%", animation: "barFill 1.1s cubic-bezier(.2,.7,.2,1) both" }} />
        </div>
        <div className="mono" style={{ display: "flex", justifyContent: "space-between", fontSize: 10, color: "#999", marginTop: 6 }}>
          <span>{Math.round((PROJECT.progress || 0) * 100)}% exec.</span>
          <span>{(() => {
            if (!PROJECT.endDate) return "—";
            try {
              const end = new Date(String(PROJECT.endDate).slice(0,10) + "T12:00:00");
              const today = new Date(); today.setHours(0,0,0,0);
              const days = Math.max(0, Math.round((end - today) / 86400000));
              return days + " dias";
            } catch { return "—"; }
          })()}</span>
        </div>
      </div>

      <div className="nav-section">Painel</div>
      <div className="nav-list" ref={navRef} style={{ position: "relative" }}>
        <span
          className="nav-indicator"
          style={{
            top: indicator.top,
            height: indicator.height,
            opacity: indicator.visible ? 1 : 0,
          }}
        />
        {enabledNav().map(item => {
          const IconC = I[item.icon];
          return (
            <button
              key={item.id}
              data-nav={item.id}
              className={"nav-item " + (active === item.id ? "active" : "")}
              onClick={() => onNav(item.id)}
            >
              <IconC size={15} />
              <span>{item.label}</span>
              <span className="kbd">{item.kbd}</span>
            </button>
          );
        })}
      </div>

      <div className="sidebar-footer">
        <div className="user-chip">
          <div className="user-avatar">{initials}</div>
          <div style={{ flex: 1, minWidth: 0 }}>
            <div className="user-name" style={{ whiteSpace: "nowrap", overflow: "hidden", textOverflow: "ellipsis" }}>
              {displayName}
            </div>
            <div className="user-role">{displayRole}</div>
          </div>
          <button className="icon-btn" title="Sair" onClick={onLogout}><I.Logout size={14} /></button>
        </div>
      </div>
    </aside>
  );
}

function Topbar({ active, onNav }) {
  const obra = window.PORTAL_USER ? (PROJECT.name || "Obra") : "";
  const [searchOpen, setSearchOpen] = React.useState(false);
  const [searchQ, setSearchQ] = React.useState("");
  const [bellOpen, setBellOpen] = React.useState(false);

  // Busca local (diarios + documentos) — navega para a pagina ao clicar em um resultado.
  const searchResults = React.useMemo(() => {
    const q = searchQ.trim().toLowerCase();
    if (!q) return [];
    const out = [];
    for (const d of DIARIES) {
      const hay = [d.id, d.date, d.statusLabel, d.note, (d.activities || []).join(" ")].join(" ").toLowerCase();
      if (hay.includes(q)) out.push({ type: "diario", label: d.id + " · " + fmtDateShort(d.date), sub: (d.activities[0] || "").slice(0, 80), target: "diarios" });
      if (out.length >= 6) break;
    }
    for (const doc of DOCS_OBRA.concat(DOCS_EQUIPE)) {
      if (out.length >= 10) break;
      if (doc.name.toLowerCase().includes(q)) out.push({ type: "documento", label: doc.name, sub: doc.category + " · " + doc.size, target: "documentos" });
    }
    return out;
  }, [searchQ]);

  // Fecha popovers ao trocar de pagina
  React.useEffect(() => { setSearchOpen(false); setBellOpen(false); }, [active]);

  // Esc fecha popovers
  React.useEffect(() => {
    const onKey = (e) => { if (e.key === "Escape") { setSearchOpen(false); setBellOpen(false); } };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, []);

  const notifications = React.useMemo(() => {
    const out = [];
    // Proximo marco
    for (const m of MILESTONES.slice(0, 3)) {
      out.push({
        title: m.label,
        body: m.fin ? "Compromisso financeiro em " + m.days + " dias" : "Marco em " + m.days + " dias",
        date: m.date, target: m.fin ? "financeiro" : "cronograma",
        kind: m.fin ? "fin" : "marco",
      });
    }
    // Ultimo diario
    if (DIARIES[0]) {
      const d = DIARIES[0];
      out.push({
        title: "Novo diario de obra",
        body: (d.activities[0] || d.statusLabel).slice(0, 100),
        date: d.date, target: "diarios", kind: "diario",
      });
    }
    // Proxima parcela nao paga
    const nextParc = (FIN.installments || []).find((p) => p.status !== "paid");
    if (nextParc) {
      out.push({
        title: "Parcela " + nextParc.n + " em aberto",
        body: fmtBRL(nextParc.amount) + " · venc. " + fmtDate(nextParc.due),
        date: nextParc.due, target: "financeiro", kind: "parcela",
      });
    }
    return out.slice(0, 5);
  }, []);

  return (
    <div className="topbar">
      <div className="breadcrumbs">
        <span>{obra}</span>
        <span className="sep">/</span>
        <span key={active} className="current crumb-anim">{NAV_LABELS[active]}</span>
      </div>

      <div className="topbar-actions">
        <div style={{ display: "flex", alignItems: "center", gap: 10, marginRight: 8, paddingRight: 12, borderRight: "1px solid var(--border)" }}>
          <span className="status-dot live" />
          <span className="mono" style={{ fontSize: 11, color: "#666" }}>canteiro ativo</span>
        </div>

        {/* Search */}
        <div style={{ position: "relative" }}>
          <button className="icon-btn" onClick={() => setSearchOpen((v) => !v)} title="Buscar (Esc fecha)">
            <I.Search size={15} />
          </button>
          {searchOpen && (
            <div style={{
              position: "absolute", right: 0, top: "calc(100% + 6px)",
              background: "#fff", border: "1px solid var(--border)", borderRadius: 8,
              padding: 10, width: 360, boxShadow: "0 10px 30px rgba(0,0,0,0.08)", zIndex: 30,
            }}>
              <input
                type="text"
                autoFocus
                value={searchQ}
                onChange={(e) => setSearchQ(e.target.value)}
                placeholder="Buscar diarios, documentos, datas..."
                style={{
                  width: "100%", border: "1px solid var(--border)", borderRadius: 6,
                  padding: "8px 10px", fontSize: 13, marginBottom: 8, outline: "none",
                }}
              />
              <div style={{ maxHeight: 320, overflow: "auto" }}>
                {searchQ.trim() === "" ? (
                  <div style={{ color: "#999", fontSize: 12, padding: "10px 4px" }}>
                    Digite ao menos 2 caracteres para buscar.
                  </div>
                ) : searchResults.length === 0 ? (
                  <div style={{ color: "#999", fontSize: 12, padding: "10px 4px" }}>
                    Nenhum resultado encontrado.
                  </div>
                ) : searchResults.map((r, i) => (
                  <button
                    key={i}
                    onClick={() => { setSearchOpen(false); setSearchQ(""); onNav && onNav(r.target); }}
                    style={{
                      display: "flex", flexDirection: "column", alignItems: "flex-start",
                      width: "100%", padding: "8px 10px", border: "none", background: "transparent",
                      borderRadius: 6, cursor: "pointer", textAlign: "left",
                    }}
                    onMouseEnter={(e) => e.currentTarget.style.background = "#FAFAFA"}
                    onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}
                  >
                    <div style={{ display: "flex", gap: 6, alignItems: "center" }}>
                      <span className="pill" style={{ fontSize: 9, height: 16 }}>{r.type}</span>
                      <span style={{ fontSize: 13, fontWeight: 500 }}>{r.label}</span>
                    </div>
                    <div style={{ fontSize: 11, color: "#666", marginTop: 2 }}>{r.sub}</div>
                  </button>
                ))}
              </div>
            </div>
          )}
        </div>

        {/* Notificacoes */}
        <div style={{ position: "relative" }}>
          <button className="icon-btn" onClick={() => setBellOpen((v) => !v)} style={{ position: "relative" }} title="Notificacoes">
            <I.Bell size={15} />
            {notifications.length > 0 && <span className="notif-dot" />}
          </button>
          {bellOpen && (
            <div style={{
              position: "absolute", right: 0, top: "calc(100% + 6px)",
              background: "#fff", border: "1px solid var(--border)", borderRadius: 8,
              width: 340, boxShadow: "0 10px 30px rgba(0,0,0,0.08)", zIndex: 30,
            }}>
              <div style={{ padding: "10px 14px", borderBottom: "1px solid var(--border)", display: "flex", justifyContent: "space-between", alignItems: "center" }}>
                <span style={{ fontSize: 12, fontWeight: 600 }}>Novidades</span>
                <span className="mono" style={{ fontSize: 10, color: "#999" }}>{notifications.length}</span>
              </div>
              {notifications.length === 0 ? (
                <div style={{ padding: "20px 14px", color: "#999", fontSize: 12, textAlign: "center" }}>
                  Nada novo por enquanto.
                </div>
              ) : notifications.map((n, i) => (
                <button
                  key={i}
                  onClick={() => { setBellOpen(false); onNav && onNav(n.target); }}
                  style={{
                    display: "flex", gap: 10, width: "100%", padding: "10px 14px",
                    border: "none", background: "transparent", cursor: "pointer", textAlign: "left",
                    borderBottom: i < notifications.length - 1 ? "1px solid var(--border)" : "none",
                  }}
                  onMouseEnter={(e) => e.currentTarget.style.background = "#FAFAFA"}
                  onMouseLeave={(e) => e.currentTarget.style.background = "transparent"}
                >
                  <div style={{
                    width: 30, height: 30, borderRadius: 8, background: n.kind === "fin" ? "#FEF3C7" : n.kind === "parcela" ? "#FEE2E2" : "#F5F5F5",
                    display: "flex", alignItems: "center", justifyContent: "center", flexShrink: 0,
                  }}>
                    {n.kind === "fin" || n.kind === "parcela" ? <I.Wallet size={14} /> : n.kind === "marco" ? <I.Calendar size={14} /> : <I.Book size={14} />}
                  </div>
                  <div style={{ flex: 1, minWidth: 0 }}>
                    <div style={{ fontSize: 12.5, fontWeight: 500, color: "#0A0A0A" }}>{n.title}</div>
                    <div style={{ fontSize: 11, color: "#666", marginTop: 2, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>{n.body}</div>
                    {n.date && <div className="mono" style={{ fontSize: 10, color: "#999", marginTop: 3 }}>{fmtDate(n.date)}</div>}
                  </div>
                </button>
              ))}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}

// Page transition wrapper
function PageTransition({ pageKey, children }) {
  return (
    <div key={pageKey} className="page-transition">
      {children}
    </div>
  );
}

// Tweaks panel
const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "density": "comfortable",
  "sidebar": "full",
  "motion": "refined"
}/*EDITMODE-END*/;

function TweaksPanel({ open, state, setState }) {
  if (!open) return null;
  const Row = ({ label, options, k }) => (
    <div className="tweaks-row">
      <label>{label}</label>
      <div className="seg">
        {options.map(o => (
          <button key={o.v} className={state[k] === o.v ? "on" : ""} onClick={() => setState(k, o.v)}>{o.lbl}</button>
        ))}
      </div>
    </div>
  );
  return (
    <div className="tweaks" style={{ animation: "tweakIn .22s cubic-bezier(.2,.7,.2,1) both" }}>
      <h5><span>Tweaks</span><span className="mono" style={{ color: "#bdbdbd" }}>v1</span></h5>
      <Row label="Densidade" k="density" options={[{ v: "compact", lbl: "compacta" }, { v: "comfortable", lbl: "confort." }]} />
      <Row label="Sidebar" k="sidebar" options={[{ v: "full", lbl: "full" }, { v: "mini", lbl: "mini" }]} />
      <Row label="Movimento" k="motion" options={[{ v: "refined", lbl: "refinado" }, { v: "reduced", lbl: "reduzido" }]} />
    </div>
  );
}

function useIsMobile() {
  const [isMobile, setIsMobile] = React.useState(() => window.innerWidth < 768);
  React.useEffect(() => {
    const mq = window.matchMedia("(max-width: 767px)");
    const onChange = (e) => setIsMobile(e.matches);
    mq.addEventListener ? mq.addEventListener("change", onChange) : mq.addListener(onChange);
    return () => {
      mq.removeEventListener ? mq.removeEventListener("change", onChange) : mq.removeListener(onChange);
    };
  }, []);
  return isMobile;
}

function FullPageLoader({ label }) {
  return (
    <div style={{
      position: "fixed", inset: 0, display: "flex", alignItems: "center",
      justifyContent: "center", background: "#FFFFFF", zIndex: 9999,
      flexDirection: "column", gap: 14,
    }}>
      <div style={{
        width: 36, height: 36, border: "3px solid #EAEAEA",
        borderTopColor: "#0A0A0A", borderRadius: "50%",
        animation: "portalSpin 0.9s linear infinite",
      }} />
      <div style={{ fontSize: 12, color: "#666", letterSpacing: "0.04em" }}>
        {label || "Carregando..."}
      </div>
      <style>{`@keyframes portalSpin { to { transform: rotate(360deg); } }`}</style>
    </div>
  );
}

function App() {
  const isMobile = useIsMobile();
  // 'unknown' | 'loading' | 'logged' | 'logged-out'
  const [authState, setAuthState] = React.useState("unknown");
  const [dataReady, setDataReady] = React.useState(false);
  const [active, setActive] = React.useState(() => localStorage.getItem("portal-page") || "dashboard");
  const [tweaks, setTweaks] = React.useState(TWEAK_DEFAULTS);
  const [tweaksOpen, setTweaksOpen] = React.useState(false);

  const logged = authState === "logged";

  React.useEffect(() => localStorage.setItem("portal-page", active), [active]);

  // Bootstrap: tenta reusar sessao existente do cookie HTTP-only
  React.useEffect(() => {
    let cancelled = false;
    (async () => {
      try {
        await portalApi.me(); // 200 se cookie valido
        if (cancelled) return;
        setAuthState("loading");
        const ok = await loadPortalData();
        if (cancelled) return;
        if (ok) {
          setDataReady(true);
          setAuthState("logged");
        } else {
          setAuthState("logged-out");
        }
      } catch {
        if (!cancelled) setAuthState("logged-out");
      }
    })();
    return () => { cancelled = true; };
  }, []);

  const handleLoginSuccess = React.useCallback(() => {
    setDataReady(true);
    setAuthState("logged");
  }, []);

  const handleLogout = React.useCallback(async () => {
    try { await portalApi.logout(); } catch (_) {}
    setDataReady(false);
    setAuthState("logged-out");
  }, []);

  // Motion setting toggles a data-attr on root
  React.useEffect(() => {
    document.documentElement.dataset.motion = tweaks.motion || "refined";
  }, [tweaks.motion]);

  // Edit mode bridge
  React.useEffect(() => {
    const onMsg = (e) => {
      const d = e.data || {};
      if (d.type === "__activate_edit_mode") setTweaksOpen(true);
      if (d.type === "__deactivate_edit_mode") setTweaksOpen(false);
    };
    window.addEventListener("message", onMsg);
    try { window.parent.postMessage({ type: "__edit_mode_available" }, "*"); } catch (_) {}
    return () => window.removeEventListener("message", onMsg);
  }, []);

  const setTweak = (k, v) => {
    setTweaks(prev => {
      const next = { ...prev, [k]: v };
      try { window.parent.postMessage({ type: "__edit_mode_set_keys", edits: { [k]: v } }, "*"); } catch (_) {}
      return next;
    });
  };

  // Keyboard shortcuts
  React.useEffect(() => {
    const onKey = (e) => {
      if (!logged) return;
      if (e.target.tagName === "INPUT" || e.target.tagName === "TEXTAREA") return;
      const hit = NAV.find(n => n.kbd.toLowerCase() === e.key.toLowerCase());
      if (hit && isModuleEnabled(hit.id)) setActive(hit.id);
    };
    window.addEventListener("keydown", onKey);
    return () => window.removeEventListener("keydown", onKey);
  }, [logged]);

  if (authState === "unknown") {
    return <FullPageLoader label="Verificando sessao..." />;
  }

  if (authState === "loading") {
    return <FullPageLoader label="Carregando dados da obra..." />;
  }

  if (!logged) {
    return (
      <>
        {isMobile
          ? <MobileLogin onLogin={handleLoginSuccess} />
          : <LoginPage onLogin={handleLoginSuccess} />}
        <TweaksPanel open={tweaksOpen} state={tweaks} setState={setTweak} />
      </>
    );
  }

  if (!dataReady) {
    return <FullPageLoader label="Preparando portal..." />;
  }

  if (isMobile) {
    return (
      <>
        <MobileApp onLogout={handleLogout} />
        <TweaksPanel open={tweaksOpen} state={tweaks} setState={setTweak} />
      </>
    );
  }

  // Se a página ativa foi desabilitada pelo admin, renderiza a primeira liberada
  // (derivado — não mexe no estado salvo; se o módulo voltar, volta a aparecer).
  const navEnabled = enabledNav();
  const activeAllowed = isModuleEnabled(active) && PAGES[active];
  const effectiveActive = activeAllowed ? active : (navEnabled[0]?.id || "dashboard");
  const Page = PAGES[effectiveActive] || PAGES.dashboard;

  return (
    <div className="app" data-screen-label={effectiveActive} style={{
      gridTemplateColumns: tweaks.sidebar === "mini" ? "64px 1fr" : "var(--sidebar-w) 1fr",
    }}>
      <Sidebar active={effectiveActive} onNav={setActive} onLogout={handleLogout} />
      <div className="main">
        <Topbar active={effectiveActive} onNav={setActive} />
        <PageTransition pageKey={effectiveActive}>
          <Page onNav={setActive} />
        </PageTransition>
      </div>
      <TweaksPanel open={tweaksOpen} state={tweaks} setState={setTweak} />
    </div>
  );
}

// Guard: Babel standalone re-processa scripts quando o DOM muda, e o brand
// patcher (strucon-brand.jsx) usa MutationObserver que pode disparar novamente
// a execucao do app.jsx em alguns navegadores. Reutilizamos o root existente
// em vez de criar um novo — evita o warning "createRoot() on a container that
// has already been passed to createRoot() before" + NotFoundError.
(() => {
  const rootEl = document.getElementById("root");
  if (!rootEl) return;
  if (!rootEl.__portalReactRoot) {
    rootEl.__portalReactRoot = ReactDOM.createRoot(rootEl);
  }
  rootEl.__portalReactRoot.render(<App />);
})();
