// Top-level app, orchestration loop, theme, tweaks

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/{
  "theme": "light",
  "density": "comfortable",
  "accentHue": 280,
  "autoFlow": true,
  "showAgentChip": true
}/*EDITMODE-END*/;

function CreateTaskModal({ onCreate, onClose }) {
  const projects = window.ORC_DATA.PROJECTS || [];
  const agents = window.ORC_DATA.AGENTS || [];
  const [form, setForm] = React.useState({
    title: '',
    project: projects[0]?.id || '',
    type: 'module-install',
    agent: agents[0]?.id || 'installer-agent',
    priority: 'medium',
    version: '',
    repo: 'sandbox/app',
    prompt: '',
    affectsDb: false,
    requiresApproval: true,
  });
  const set = (k, v) => setForm(f => ({ ...f, [k]: v }));
  const valid = form.title.trim() && form.project;
  const isCli = (window.ORC_DATA.AGENTS || []).find(a => a.id === form.agent)?.kind === 'codex'
    || (window.ORC_DATA.AGENTS || []).find(a => a.id === form.agent)?.kind === 'gemini';

  function submit() {
    if (!valid) return;
    const payload = {
      repo: form.repo || 'sandbox/app',
      branch: 'main',
      module: 'hello',
      targetVersion: form.version || undefined,
      prompt: form.prompt.trim() || undefined,
    };
    onCreate({
      title: form.title.trim(),
      project: form.project,
      agent: form.agent,
      type: form.type,
      priority: form.priority,
      version: form.version,
      affectsDb: form.affectsDb,
      requiresApproval: form.requiresApproval,
      payload,
    });
    onClose();
  }

  return (
    <div className="modal-overlay" onClick={onClose}>
      <div className="panel" style={{ width: 460, maxWidth: '90vw' }} onClick={e => e.stopPropagation()}>
        <div className="panel-head">
          <span className="panel-title"><Icon name="plus" size={13} /> New task</span>
          <button className="icon-btn" type="button" onClick={onClose}><Icon name="close" size={14} /></button>
        </div>
        <div className="panel-body" style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          <div className="set-field">
            <label>Title</label>
            <input className="input" value={form.title} autoFocus
              placeholder="Install Billing module v1.2.0"
              onChange={e => set('title', e.target.value)} />
          </div>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
            <div className="set-field">
              <label>Project</label>
              <select className="select" value={form.project} onChange={e => set('project', e.target.value)}>
                {projects.map(p => <option key={p.id} value={p.id}>{p.name}</option>)}
              </select>
            </div>
            <div className="set-field">
              <label>Agent</label>
              <select className="select" value={form.agent} onChange={e => set('agent', e.target.value)}>
                {agents.map(a => <option key={a.id} value={a.id}>{a.id}</option>)}
              </select>
            </div>
            <div className="set-field">
              <label>Type</label>
              <select className="select" value={form.type} onChange={e => set('type', e.target.value)}>
                <option value="module-install">Module Install</option>
                <option value="update">Update</option>
                <option value="agent-task">Agent Task</option>
                <option value="system-task">System Task</option>
              </select>
            </div>
            <div className="set-field">
              <label>Priority</label>
              <select className="select" value={form.priority} onChange={e => set('priority', e.target.value)}>
                <option value="high">High</option>
                <option value="medium">Medium</option>
                <option value="low">Low</option>
              </select>
            </div>
          </div>
          <div className="set-field">
            <label>Version</label>
            <input className="input" value={form.version} placeholder="v1.0.0"
              onChange={e => set('version', e.target.value)} />
          </div>
          <div className="set-field">
            <label>Repo</label>
            <input className="input" value={form.repo} placeholder="sandbox/app"
              onChange={e => set('repo', e.target.value)} />
          </div>
          {isCli && (
            <div className="set-field">
              <label>Prompt (instructions for the agent)</label>
              <textarea className="input" rows={4} value={form.prompt}
                placeholder="e.g. Add a CONTRIBUTING.md with a short setup guide"
                onChange={e => set('prompt', e.target.value)} style={{ resize: 'vertical', minHeight: 70 }} />
            </div>
          )}
          <div style={{ display: 'flex', gap: 18 }}>
            <label style={{ display: 'flex', alignItems: 'center', gap: 8, cursor: 'pointer' }}>
              <input type="checkbox" checked={form.affectsDb} onChange={e => set('affectsDb', e.target.checked)} />
              <span>Affects DB</span>
            </label>
            <label style={{ display: 'flex', alignItems: 'center', gap: 8, cursor: 'pointer' }}>
              <input type="checkbox" checked={form.requiresApproval} onChange={e => set('requiresApproval', e.target.checked)} />
              <span>Requires approval</span>
            </label>
          </div>
        </div>
        <div className="panel-head" style={{ justifyContent: 'flex-end', gap: 8, borderTop: '1px solid var(--c-line)', borderBottom: 'none' }}>
          <button className="btn ghost" type="button" onClick={onClose}>Cancel</button>
          <button className="btn primary" type="button" disabled={!valid} onClick={submit}>
            <Icon name="plus" size={12} /> Create
          </button>
        </div>
      </div>
    </div>
  );
}

function App() {
  const [tweaks, setTweak] = window.useTweaks(TWEAK_DEFAULTS);
  const [view, setView] = React.useState('board');
  const [boardTab, setBoardTab] = React.useState('kanban');
  const [projectId, setProjectId] = React.useState(null);
  const [tasks, setTasks] = React.useState([]);
  const [selectedId, setSelectedId] = React.useState(null);
  const [animMap, setAnimMap] = React.useState({});
  const [toasts, setToasts] = React.useState([]);
  const [loadErr, setLoadErr] = React.useState(null);
  const [showCreate, setShowCreate] = React.useState(false);
  const [live, setLive] = React.useState(false);
  const [logsByTask, setLogsByTask] = React.useState({});

  // Theme
  React.useEffect(() => {
    document.documentElement.dataset.theme = tweaks.theme;
  }, [tweaks.theme]);

  // Accent
  React.useEffect(() => {
    const root = document.documentElement;
    root.style.setProperty('--c-accent', `oklch(0.58 0.19 ${tweaks.accentHue})`);
    root.style.setProperty('--c-accent-hi', `oklch(0.66 0.19 ${tweaks.accentHue})`);
    root.style.setProperty('--c-accent-bg', `oklch(0.96 0.03 ${tweaks.accentHue})`);
    root.style.setProperty('--c-accent-line', `oklch(0.88 0.06 ${tweaks.accentHue})`);
    if (tweaks.theme === 'dark') {
      root.style.setProperty('--c-accent', `oklch(0.7 0.18 ${tweaks.accentHue})`);
      root.style.setProperty('--c-accent-bg', `oklch(0.28 0.06 ${tweaks.accentHue})`);
    }
  }, [tweaks.accentHue, tweaks.theme]);

  // Density
  React.useEffect(() => {
    document.documentElement.style.setProperty(
      '--header-h',
      tweaks.density === 'compact' ? '42px' : tweaks.density === 'spacious' ? '56px' : '48px'
    );
  }, [tweaks.density]);

  const selected = tasks.find(t => t.id === selectedId);
  const project = projectId ? window.ORC_DATA.PROJECTS.find(p => p.id === projectId) : null;

  // Toast helpers
  const pushToast = React.useCallback((toast) => {
    const id = Math.random().toString(36).slice(2);
    setToasts(t => [...t, { ...toast, id }]);
    setTimeout(() => {
      setToasts(t => t.map(x => x.id === id ? { ...x, leaving: true } : x));
      setTimeout(() => setToasts(t => t.filter(x => x.id !== id)), 250);
    }, 3600);
  }, []);

  // Animate column transitions
  const animateMove = React.useCallback((id) => {
    setAnimMap(m => ({ ...m, [id]: 'entering' }));
    setTimeout(() => setAnimMap(m => { const n = { ...m }; delete n[id]; return n; }), 420);
  }, []);

  // Load board from backend; hydrate ORC_DATA so child components keep working.
  const refresh = React.useCallback(async () => {
    try {
      const board = await window.ORC_API.getBoard();
      window.ORC_DATA.COLUMNS = board.columns;
      window.ORC_DATA.PROJECTS = board.projects;
      window.ORC_DATA.AGENTS = board.agents;
      setTasks(board.tasks);
      setLoadErr(null);
    } catch (e) {
      setLoadErr(e.message || 'failed to reach API');
    }
  }, []);

  // Initial load
  React.useEffect(() => { refresh(); }, [refresh]);

  // Live stream (SSE) — autoFlow toggle pauses/resumes the connection
  React.useEffect(() => {
    if (!tweaks.autoFlow) { setLive(false); return; }
    const es = window.ORC_API.stream(ev => {
      if (ev.type === 'task') {
        setTasks(curr => {
          const i = curr.findIndex(t => t.id === ev.task.id);
          if (i < 0) return [ev.task, ...curr];
          if (curr[i].column !== ev.task.column) animateMove(ev.task.id);
          const n = [...curr]; n[i] = ev.task; return n;
        });
      } else if (ev.type === 'log') {
        setLogsByTask(m => {
          const arr = m[ev.taskId] || [];
          if (arr.some(l => String(l.id) === String(ev.log.id))) return m;
          return { ...m, [ev.taskId]: [...arr, ev.log] };
        });
      }
    });
    es.onopen = () => setLive(true);
    es.onerror = () => setLive(false);
    return () => es.close();
  }, [tweaks.autoFlow, animateMove]);

  // Seed log history when a task is opened
  React.useEffect(() => {
    if (!selectedId) return;
    window.ORC_API.getLogs(selectedId).then(rows => {
      setLogsByTask(m => {
        const liveExtra = (m[selectedId] || []).filter(l => !rows.some(r => String(r.id) === String(l.id)));
        return { ...m, [selectedId]: [...rows, ...liveExtra].sort((a, b) => Number(a.id) - Number(b.id)) };
      });
    }).catch(() => {});
  }, [selectedId]);

  // Action handlers — call API, then refresh + toast
  const runAction = React.useCallback(async (fn, ok) => {
    try {
      await fn();
      await refresh();
      if (ok) pushToast(ok);
    } catch (e) {
      pushToast({ tone: 'fail', title: 'Action failed', msg: e.message || 'error' });
    }
  }, [refresh, pushToast]);

  const handleApprove = React.useCallback((id) =>
    runAction(() => window.ORC_API.approve(id), { tone: 'ok', title: 'Approved', msg: `<b>${id}</b> → Done` }),
    [runAction]);
  const handleReject = React.useCallback((id) =>
    runAction(() => window.ORC_API.reject(id), { tone: 'fail', title: 'Rejected', msg: `<b>${id}</b> → Failed` }),
    [runAction]);
  const handleTransition = React.useCallback((id, to) => {
    animateMove(id);
    return runAction(() => window.ORC_API.transition(id, to), { tone: to === 'failed' ? 'fail' : 'info', title: 'Moved', msg: `<b>${id}</b> → ${to}` });
  }, [runAction, animateMove]);
  const handleCreate = React.useCallback((body) =>
    runAction(() => window.ORC_API.createTask(body), { tone: 'info', title: 'Task created', msg: `<b>${body.title}</b> → Backlog` }),
    [runAction]);

  const actions = { approve: handleApprove, reject: handleReject, transition: handleTransition };

  const visibleTasks = React.useMemo(() => {
    if (view === 'board' && projectId) return tasks.filter(t => t.project === projectId);
    return tasks;
  }, [tasks, view, projectId]);

  function handleNav(id, pid) {
    setView(id);
    if (id === 'projects' && pid) setProjectId(pid);
    if (id === 'board') {} // keep filter
    setSelectedId(null);
  }

  return (
    <div className="app">
      <Sidebar
        active={view}
        onNav={handleNav}
        projects={window.ORC_DATA.PROJECTS}
        currentProject={view === 'projects' ? projectId : null}
      />
      <Topbar
        view={view}
        project={project}
        onProjectClick={() => {}}
        onThemeToggle={() => setTweak('theme', tweaks.theme === 'dark' ? 'light' : 'dark')}
        theme={tweaks.theme}
      />
      <main className="main">
        {view === 'board' && (
          <>
            <div className="subbar">
              <button className={`tab ${boardTab === 'kanban' ? 'active' : ''}`} type="button" onClick={() => setBoardTab('kanban')}>
                <Icon name="columns" size={12} />Kanban<span className="count">{visibleTasks.length}</span>
              </button>
              <button className={`tab ${boardTab === 'timeline' ? 'active' : ''}`} type="button" onClick={() => setBoardTab('timeline')}>
                <Icon name="layers" size={12} />Timeline
              </button>
              <button className={`tab ${boardTab === 'activity' ? 'active' : ''}`} type="button" onClick={() => setBoardTab('activity')}>
                <Icon name="log" size={12} />Activity
              </button>

              <span style={{ width: 1, height: 18, background: 'var(--c-line)', margin: '0 4px' }} />

              <span className="chip"><Icon name="filter" size={12} />Project · {project?.name || 'all'}</span>
              <span className="chip dim"><Icon name="cpu" size={12} />Agents · all</span>
              <span className="chip dim"><Icon name="flag" size={12} />Priority · any</span>

              <span style={{ marginLeft: 'auto', display: 'flex', gap: 6, alignItems: 'center' }}>
                <span className="chip chip-mono">
                  <span className={`dot ${live ? 'pulse' : ''}`} style={{ color: live ? 'var(--c-status-done)' : 'var(--c-text-3)' }} />
                  {live ? 'orchestrator live' : tweaks.autoFlow ? 'connecting…' : 'paused'}
                </span>
                <button className="btn ghost" type="button" onClick={() => setTweak('autoFlow', !tweaks.autoFlow)}>
                  <Icon name={tweaks.autoFlow ? 'pause' : 'play'} size={12} />
                  {tweaks.autoFlow ? 'Pause flow' : 'Resume'}
                </button>
                <button className="btn" type="button"><Icon name="sliders" size={12} />Sort</button>
                <button className="btn primary" type="button" onClick={() => setShowCreate(true)}><Icon name="plus" size={12} />New task</button>
              </span>
            </div>
            {loadErr && (
              <div className="empty" style={{ margin: '12px 20px', color: 'var(--c-status-failed)', borderColor: 'var(--c-status-failed)' }}>
                <Icon name="alert" size={12} /> API unreachable — {loadErr} · base {window.ORC_API.base}
              </div>
            )}
            {boardTab === 'kanban' && (
              <Board
                tasks={visibleTasks}
                onSelect={setSelectedId}
                selectedId={selectedId}
                animMap={animMap}
                actions={actions}
              />
            )}
            {boardTab === 'timeline' && (
              <window.TimelineView
                tasks={visibleTasks}
                onSelect={setSelectedId}
                selectedId={selectedId}
              />
            )}
            {boardTab === 'activity' && (
              <window.ActivityView onSelect={setSelectedId} />
            )}
            <DetailPanel task={selected} onClose={() => setSelectedId(null)} actions={actions} logs={logsByTask[selectedId]} />
          </>
        )}

        {view === 'projects' && (
          <ProjectPage
            projectId={projectId || 'vidix'}
            onOpenBoard={() => { setView('board'); }}
          />
        )}

        {view === 'modules' && <ModuleLibrary />}
        {view === 'agents' && <window.AgentsScreen />}

        {view === 'kb' && <window.KnowledgeBase />}

        {view === 'settings' && <window.SettingsPage />}
      </main>

      <div className="toast-wrap">
        {toasts.map(t => (
          <div key={t.id} className={`toast ${t.tone === 'ok' ? 'ok' : t.tone === 'fail' ? 'fail' : t.tone === 'review' ? 'review' : ''} ${t.leaving ? 'leaving' : ''}`}>
            <span className="dot" />
            <div>
              <b>{t.title}</b>
              <div className="toast-msg" dangerouslySetInnerHTML={{ __html: t.msg }} />
            </div>
          </div>
        ))}
      </div>

      {showCreate && <CreateTaskModal onCreate={handleCreate} onClose={() => setShowCreate(false)} />}

      <window.TweaksPanel title="Tweaks">
        <window.TweakSection title="Appearance">
          <window.TweakRadio
            label="Theme"
            value={tweaks.theme}
            onChange={v => setTweak('theme', v)}
            options={[{ value: 'light', label: 'Light' }, { value: 'dark', label: 'Dark' }]}
          />
          <window.TweakRadio
            label="Density"
            value={tweaks.density}
            onChange={v => setTweak('density', v)}
            options={[{ value: 'compact', label: 'Compact' }, { value: 'comfortable', label: 'Default' }, { value: 'spacious', label: 'Spacious' }]}
          />
          <window.TweakSlider
            label="Accent hue"
            min={0} max={360} step={5}
            value={tweaks.accentHue}
            onChange={v => setTweak('accentHue', v)}
          />
        </window.TweakSection>
        <window.TweakSection title="Orchestration">
          <window.TweakToggle
            label="Auto-flow simulation"
            checked={tweaks.autoFlow}
            onChange={v => setTweak('autoFlow', v)}
          />
          <window.TweakToggle
            label="Show agent chip on cards"
            checked={tweaks.showAgentChip}
            onChange={v => setTweak('showAgentChip', v)}
          />
        </window.TweakSection>
      </window.TweaksPanel>
    </div>
  );
}

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