// app.jsx — Idea Pipeline shell, state, routing, tweaks

const { useState, useEffect, useMemo } = React;
const { PROJECTS, USERS } = window.SEED;

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "violet",
  "dark": false,
  "density": "regular",
  "font": "Plus Jakarta Sans"
}/*EDITMODE-END*/;

const THEMES = {
  violet: 275, blue: 248, teal: 192, green: 152, amber: 60, rose: 12,
};

function App() {
  const [t, setTweak] = window.useTweaks(TWEAK_DEFAULTS);
  const [authUser, setAuthUser] = useState(null);
  const [booting, setBooting] = useState(true);   // resolving session / loading workspace
  const [loadErr, setLoadErr] = useState('');
  const [projects, setProjects] = useState([]);
  const [roles, setRoles] = useState({});
  const [view, setView] = useState('ideas');           // ideas | project | mytasks | roles
  const [activeId, setActiveId] = useState(null);
  const [open, setOpen] = useState(null);              // { projectId, taskId }
  const [newIdea, setNewIdea] = useState(false);
  const [query, setQuery] = useState('');
  const [projTab, setProjTab] = useState('board');     // board | report

  // apply theme tokens
  useEffect(() => {
    const r = document.documentElement;
    r.dataset.dark = t.dark ? '1' : '0';
    r.dataset.density = t.density;
    r.style.setProperty('--primary-h', THEMES[t.theme] ?? 275);
    r.style.setProperty('--font-ui', `'${t.font}', system-ui, sans-serif`);
  }, [t.theme, t.dark, t.density, t.font]);

  // ---- pull the live workspace from Supabase and prime app state ----
  const boot = async (uid) => {
    setBooting(true); setLoadErr('');
    try {
      const ws = await window.IPDB.loadWorkspace();
      // Repopulate window.SEED.USERS *in place* — components.jsx / views.jsx /
      // roles.jsx / board.jsx all captured this array reference at load time.
      const U = window.SEED.USERS;
      U.length = 0; ws.users.forEach((u) => U.push(u));
      window.SEED.ME = uid;
      setProjects(ws.projects);
      setRoles(ws.roles);
      setAuthUser(uid);
    } catch (e) {
      setLoadErr((e && e.message) || 'Failed to load workspace.');
    } finally {
      setBooting(false);
    }
  };

  // resolve an existing session on first mount; react to sign-out elsewhere
  useEffect(() => {
    let sub;
    (async () => {
      if (!window.db) { setBooting(false); setLoadErr('Backend not connected.'); return; }
      const { data } = await window.db.auth.getSession();
      if (data.session) await boot(data.session.user.id);
      else setBooting(false);
      sub = window.db.auth.onAuthStateChange((_evt, session) => {
        if (!session) { setAuthUser(null); setProjects([]); setRoles({}); }
      }).data.subscription;
    })();
    return () => { if (sub) sub.unsubscribe(); };
  }, []);

  const login = (id) => boot(id);
  const logout = async () => {
    try { await window.db.auth.signOut(); } catch (e) {}
    setAuthUser(null); setProjects([]); setRoles({});
    setView('ideas'); setActiveId(null); setOpen(null);
  };

  // ---- gates ----
  if (booting) return <BootScreen />;
  if (!authUser) return <window.Login onLogin={login} error={loadErr} />;
  window.SEED.ME = authUser;
  const ME = authUser;
  const myRole = roles[ME];
  const canCreate = window.can(myRole, 'Create a new idea');

  const active = projects.find((p) => p.id === activeId);
  const openTask = open && projects.find((p) => p.id === open.projectId)?.tasks.find((x) => x.id === open.taskId);
  const openProject = open && projects.find((p) => p.id === open.projectId);

  // ---- mutations ----
  // UI updates optimistically; every change is persisted to Supabase (RLS
  // decides what actually sticks). Writes that mint new rows await the DB so
  // local ids match the real UUIDs.
  const warn = (e) => { if (e && e.error) console.warn('[IdeaPipeline] write rejected:', e.error.message); };

  const mutateTasks = (projectId, fn) =>
    setProjects((ps) => ps.map((p) => p.id === projectId ? { ...p, tasks: fn(p.tasks) } : p));

  const moveTask = (taskId, stage) => {
    setProjects((ps) => ps.map((p) => ({ ...p, tasks: p.tasks.map((x) => x.id === taskId ? { ...x, stage } : x) })));
    window.IPDB.moveTask(taskId, stage).then(warn);
  };

  const updateTask = (projectId, taskId, patch) => {
    mutateTasks(projectId, (tasks) => tasks.map((x) => x.id === taskId ? { ...x, ...patch } : x));
    window.IPDB.updateTask(taskId, patch).then(warn);
  };

  const addProjectComment = async (projectId, text) => {
    try {
      const c = await window.IPDB.addComment({ projectId, authorId: ME, body: text });
      setProjects((ps) => ps.map((p) => p.id === projectId ? { ...p, comments: [...(p.comments || []), c] } : p));
    } catch (e) { console.warn('[IdeaPipeline] comment failed:', e.message); }
  };
  const addTaskComment = async (projectId, taskId, text) => {
    try {
      const c = await window.IPDB.addComment({ taskId, authorId: ME, body: text });
      mutateTasks(projectId, (tasks) => tasks.map((x) => x.id === taskId ? { ...x, comments: [...(x.comments || []), c] } : x));
    } catch (e) { console.warn('[IdeaPipeline] comment failed:', e.message); }
  };

  const addTask = async (projectId, stage) => {
    const proj = projects.find((p) => p.id === projectId);
    try {
      const task = await window.IPDB.addTask(projectId, { stage, assignee: proj.team[0] });
      mutateTasks(projectId, (tasks) => [...tasks, task]);
      setOpen({ projectId, taskId: task.id });
    } catch (e) { console.warn('[IdeaPipeline] add task failed:', e.message); }
  };

  const createIdea = async (data) => {
    try {
      const project = await window.IPDB.createIdea(data);
      setProjects((ps) => [project, ...ps]);
      setNewIdea(false);
      setActiveId(project.id);
      setView('project');
    } catch (e) { console.warn('[IdeaPipeline] create idea failed:', e.message); }
  };

  // RolesView hands back the full next-roles object; persist whatever changed.
  const persistRoles = (next) => {
    Object.keys(next).forEach((uid) => {
      if (next[uid] !== roles[uid]) window.IPDB.setRole(uid, next[uid]).then(warn);
    });
    setRoles(next);
  };

  const goProject = (id) => { setActiveId(id); setView('project'); setProjTab('board'); setQuery(''); };

  return (
    <div className="app">
      {/* sidebar */}
      <nav className="sidebar">
        <div className="brand">
          <span className="brand-mark"><window.Icon name="bolt" size={18} stroke={2.2} /></span>
          <span className="brand-name">Idea<span style={{ color: 'var(--primary)' }}>Pipeline</span></span>
        </div>
        <div className="nav-group">
          <NavItem icon="grid" label="Business Ideas" on={view === 'ideas' || view === 'project'}
            onClick={() => { setView('ideas'); setQuery(''); }} />
          <NavItem icon="user" label="My Tasks" badge={projects.reduce((n, p) => n + p.tasks.filter((x) => x.assignee === ME && x.stage !== 'complete').length, 0)}
            on={view === 'mytasks'} onClick={() => { setView('mytasks'); setQuery(''); }} />
          <NavItem icon="users" label="Roles & Permissions" on={view === 'roles'}
            onClick={() => { setView('roles'); setQuery(''); }} />
        </div>

        <div className="nav-label">Active ideas</div>
        <div className="nav-group scroll">
          {projects.filter((p) => p.status !== 'launched').slice(0, 6).map((p) => (
            <button key={p.id} className={'nav-proj' + (activeId === p.id && view === 'project' ? ' on' : '')}
              onClick={() => goProject(p.id)}>
              <span className="nav-proj-dot" style={{ background: `oklch(0.6 0.15 ${window.SEED.IDEA_STATUS[p.status].hue})` }} />
              <span className="nav-proj-name">{p.name}</span>
              <span className="nav-proj-n">{p.tasks.filter((x) => x.stage !== 'complete').length}</span>
            </button>
          ))}
        </div>

        <div className="sidebar-foot">
          <window.Avatar id={ME} size={34} />
          <div style={{ minWidth: 0, flex: 1 }}>
            <div className="me-name">{window.userById(ME).name}</div>
            <div className="me-foot-role"><window.RolePill roleId={myRole} size="sm" /></div>
          </div>
          <button className="icon-btn" title="Sign out" onClick={logout}>
            <window.Icon name="logout" size={17} />
          </button>
        </div>
      </nav>

      {/* main */}
      <main className="main">
        <header className="topbar">
          {view === 'project' && active ? (
            <div className="crumbs">
              <button className="crumb-back" onClick={() => setView('ideas')}>
                <window.Icon name="chevronL" size={16} /> Ideas
              </button>
              <span className="crumb-sep">/</span>
              <span className="crumb-cur">{active.name}</span>
              <window.StatusPill status={active.status} />
            </div>
          ) : (
            <div className="searchbox">
              <window.Icon name="search" size={17} style={{ color: 'var(--text-faint)' }} />
              <input value={query} onChange={(e) => setQuery(e.target.value)}
                placeholder={view === 'mytasks' ? 'Search my tasks…' : 'Search ideas…'} />
            </div>
          )}
          <div style={{ flex: 1 }} />
          {canCreate && (
            <button className="btn-primary sm" onClick={() => setNewIdea(true)}>
              <window.Icon name="plus" size={16} /> New Idea
            </button>
          )}
        </header>

        <div className="content">
          {view === 'ideas' && (
            <window.IdeasView projects={projects} onOpen={goProject} onNew={() => setNewIdea(true)} query={query} canCreate={canCreate} />
          )}
          {view === 'roles' && (
            <window.RolesView roles={roles} setRoles={persistRoles} me={ME} />
          )}
          {view === 'project' && active && (
            <div className="project-view">
              <div className="project-hero">
                <div style={{ minWidth: 0 }}>
                  <span className="proj-mono" style={{ color: 'var(--text-faint)' }}>{active.category} · started {active.created}</span>
                  <h1 className="view-title" style={{ marginTop: 4 }}>{active.name}</h1>
                  <p className="view-sub" style={{ maxWidth: 560 }}>{active.tagline}</p>
                </div>
                <div className="hero-side">
                  <div className="hero-cost">
                    <span className="hero-cost-lbl"><window.Icon name="wallet" size={14} stroke={2} /> Total cost</span>
                    <span className="hero-cost-val">{window.fmtMoney(active.tasks.reduce((n, t) => n + (t.cost || 0), 0))}</span>
                  </div>
                  <div style={{ width: 200 }}>
                    <window.Progress value={active.tasks.filter((x) => x.stage === 'complete').length} total={active.tasks.length} />
                    <div className="hero-team">
                      <window.AvatarStack ids={active.team} size={28} max={6} />
                    </div>
                  </div>
                </div>
              </div>
              <div className="proj-tabs">
                <button className={'proj-tab' + (projTab === 'board' ? ' on' : '')} onClick={() => setProjTab('board')}>
                  <window.Icon name="board" size={16} /> Task Board
                </button>
                <button className={'proj-tab' + (projTab === 'discussion' ? ' on' : '')} onClick={() => setProjTab('discussion')}>
                  <window.Icon name="comment" size={16} /> Discussion
                  {active.comments && active.comments.length > 0 && <span className="tab-count">{active.comments.length}</span>}
                </button>
                <button className={'proj-tab' + (projTab === 'report' ? ' on' : '')} onClick={() => setProjTab('report')}>
                  <window.Icon name="receipt" size={16} /> Expense Report
                </button>
              </div>
              {projTab === 'board' && (
                <window.Board project={active} onOpen={(taskId) => setOpen({ projectId: active.id, taskId })}
                  moveTask={moveTask} onAdd={(stage) => addTask(active.id, stage)} />
              )}
              {projTab === 'discussion' && (
                <div className="discussion-scroll">
                  <div className="discussion-wrap">
                    <h2 className="disc-title">Project Discussion</h2>
                    <p className="disc-sub">Team notes & decisions for {active.name}. Separate from task-level comments.</p>
                    <div className="disc-panel">
                      <window.CommentThread comments={active.comments || []}
                        onAdd={(text) => addProjectComment(active.id, text)}
                        placeholder={`Share an update on ${active.name}…`}
                        empty="No project comments yet — kick off the discussion." autoScroll />
                    </div>
                  </div>
                </div>
              )}
              {projTab === 'report' && (
                <div className="report-scroll"><window.ExpenseReport project={active} /></div>
              )}
            </div>
          )}
          {view === 'mytasks' && (
            <window.MyTasksView projects={projects} query={query}
              onOpenTask={(projectId, taskId) => setOpen({ projectId, taskId })} />
          )}
        </div>
      </main>

      {openTask && (
        <window.TaskDrawer task={openTask} project={openProject} onClose={() => setOpen(null)}
          onChange={(patch) => updateTask(open.projectId, open.taskId, patch)}
          onAddComment={(text) => addTaskComment(open.projectId, open.taskId, text)} />
      )}
      {newIdea && <window.NewIdeaModal onClose={() => setNewIdea(false)} onCreate={createIdea} />}

      <window.TweaksPanel>
        <window.TweakSection label="Theme" />
        <window.TweakSelect label="Accent" value={t.theme}
          options={['violet', 'blue', 'teal', 'green', 'amber', 'rose']}
          onChange={(v) => setTweak('theme', v)} />
        <window.TweakToggle label="Dark mode" value={t.dark} onChange={(v) => setTweak('dark', v)} />
        <window.TweakSection label="Layout" />
        <window.TweakRadio label="Density" value={t.density}
          options={['compact', 'regular', 'comfy']} onChange={(v) => setTweak('density', v)} />
        <window.TweakSelect label="Font" value={t.font}
          options={['Plus Jakarta Sans', 'Manrope', 'Figtree', 'Inter Tight']}
          onChange={(v) => setTweak('font', v)} />
      </window.TweaksPanel>
    </div>
  );
}

function BootScreen() {
  return (
    <div className="login-stage" style={{ display: 'grid', placeItems: 'center' }}>
      <div className="login-orb" />
      <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 16, zIndex: 1 }}>
        <span className="brand-mark" style={{ width: 46, height: 46 }}>
          <window.Icon name="bolt" size={24} stroke={2.2} />
        </span>
        <div style={{ fontFamily: 'var(--font-mono)', fontSize: 13, color: 'var(--text-dim)' }}>
          Loading your workspace…
        </div>
      </div>
    </div>
  );
}

function NavItem({ icon, label, on, onClick, badge }) {
  return (
    <button className={'nav-item' + (on ? ' on' : '')} onClick={onClick}>
      <window.Icon name={icon} size={18} />
      <span>{label}</span>
      {badge > 0 && <span className="nav-badge">{badge}</span>}
    </button>
  );
}

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