// ============ Main App — API-connected ============

// ---- Auth screen ----
function AuthScreen({ error }) {
  return (
    <div className="auth-screen">
      <div className="auth-card">
        <div className="auth-logo">
          <img src="/email-agent-icon.png" alt="ATLAS Email Agent" style={{width:80,height:80,borderRadius:'50%',objectFit:'cover'}} />
        </div>
        <h1>ATLAS Email Agent</h1>
        <p>AI-powered inbox management for Elite Roads.<br/>Connect your Microsoft 365 account to get started.</p>
        {error && <div className="auth-error">{error}</div>}
        <a href="/auth/login" className="btn primary auth-btn">
          <I.ms365/> Sign in with Microsoft 365
        </a>
        <div className="auth-note">
          Requires <strong>Mail.Read</strong> and <strong>Mail.ReadWrite</strong> permissions.<br/>
          Emails are processed by Claude AI (snippets only — first 500 chars).
        </div>
      </div>
    </div>
  );
}

// ---- Sidebar ----
function Sidebar({ view, setView, counts, employee }) {
  const nav = [
    { key:'todo',     label:'To-do list',        icon:<I.inbox/>,    count:counts.todo,     section:'Inbox' },
    { key:'done',     label:'Done',              icon:<I.check/>,    count:counts.done },
    { key:'deleted',  label:'Recently Deleted',  icon:<I.trash/>,    count:counts.deleted||undefined },
    { key:'followup', label:'Follow-ups',        icon:<I.clock/>,    count:counts.followup, urgent:counts.followup>0, section:'Watching' },
    { key:'disputes', label:'Disputes & claims', icon:<I.gavel/>,    count:counts.disputes, urgent:counts.disputesEsc>0 },
    { key:'folders',  label:'Folder rules',      icon:<I.folder/>,   section:'Configuration' },
    { key:'style',    label:'Settings',          icon:<I.settings/> },
  ];

  const initials = (employee?.name || 'U').split(' ').map(w=>w[0]).slice(0,2).join('').toUpperCase();

  return (
    <aside className="sidebar">
      <div className="brand">
        <img src="/email-agent-icon.png" alt="" style={{width:36,height:36,borderRadius:'50%',objectFit:'cover',flexShrink:0}} />
        <div>
          <div className="brand-name">ATLAS Email Agent</div>
          <div className="brand-sub">elite-roads · v1.6</div>
        </div>
      </div>
      {nav.map(n => (
        <React.Fragment key={n.key}>
          {n.section && <div className="nav-section-label">{n.section}</div>}
          <button className="nav-item" aria-current={view===n.key ? 'page' : undefined} onClick={() => setView(n.key)}>
            <span className="nav-icon">{n.icon}</span>
            <span className="nav-label">{n.label}</span>
            {n.count != null && <span className={`nav-count ${n.urgent ? 'urgent' : ''}`}>{n.count}</span>}
          </button>
        </React.Fragment>
      ))}
      <div className="sidebar-foot">
        <div className="user-row">
          <div className="avatar">{initials}</div>
          <div style={{minWidth:0}}>
            <div className="user-name">{employee?.name || 'User'}</div>
            <div className="user-email" style={{whiteSpace:'nowrap', overflow:'hidden', textOverflow:'ellipsis'}}>
              {employee?.email || ''}
            </div>
          </div>
        </div>
        <button className="btn ghost sm" style={{marginTop:8, width:'100%'}}
          onClick={async () => { await api.post('/api/auth/logout', {}); location.reload(); }}>
          Sign out
        </button>
      </div>
    </aside>
  );
}

// ---- Topbar ----
function Topbar({ view, scanning, lastScan, nextScanAt, onScan }) {
  const titles = {
    todo:'To-do list', done:'Done', followup:'Follow-ups',
    disputes:'Disputes & claims', folders:'Folder rules', style:'Settings',
  };
  const [now, setNow] = useState(Date.now());
  useEffect(() => { const t = setInterval(() => setNow(Date.now()), 10000); return () => clearInterval(t); }, []);
  const mins = lastScan ? Math.round((now - new Date(lastScan)) / 60000) : null;
  const nextMins = nextScanAt ? Math.max(0, Math.round((new Date(nextScanAt) - now) / 60000)) : null;
  return (
    <header className="topbar">
      <h1>
        <span className="crumb">ATLAS Email Agent &nbsp;/&nbsp; </span>{titles[view]}
      </h1>
      <div className="topbar-spacer"/>
      <div className="scan-chip">
        <span className={`scan-dot ${scanning ? 'scanning' : ''}`}/>
        {scanning
          ? <span>Scanning inbox…</span>
          : <>
              <span>Connected · M365</span>
              {mins !== null && <span className="mono">· last scan {mins}m ago</span>}
              {nextMins !== null && <span className="mono" style={{color:'#16a34a'}}>· next in {nextMins}m</span>}
            </>
        }
      </div>
      <button className="btn" onClick={onScan} disabled={scanning}>
        {scanning ? <I.spin/> : <I.refresh/>} {scanning ? 'Scanning…' : 'Scan now'}
      </button>
    </header>
  );
}

// ---- Activity rail ----
function ActivityRail({ log, pipelineStep, stats }) {
  const steps = [
    'Fetch new emails',
    'Remove duplicates',
    'Classify & prioritise',
    'Group by thread',
    'Detect follow-ups',
    'Update to-do list',
  ];
  const logRef = useRef(null);
  useEffect(() => {
    if (logRef.current) logRef.current.scrollTop = logRef.current.scrollHeight;
  }, [log]);

  return (
    <aside className="rail">
      <h3>Agent status</h3>
      <div className="stat-row">
        <div className="stat"><div className="v">{stats?.scanned  || 0}</div><div className="l">Scanned</div></div>
        <div className="stat"><div className="v">{stats?.classified||0}</div><div className="l">Classified</div></div>
        <div className="stat"><div className="v">{stats?.moved    || 0}</div><div className="l">Moved</div></div>
      </div>

      <h3>Scan pipeline</h3>
      <div className="rail-card">
        <div className="pipeline">
          {steps.map((s, i) => {
            const status = pipelineStep > i ? 'done' : pipelineStep === i ? 'active' : 'idle';
            return (
              <div className={`pipe-step ${status}`} key={i}>
                <span className="n">{String(i+1).padStart(2,'0')}</span>
                <span className="label">{s}</span>
                <span className="status">{status==='done' ? '✓ ok' : status==='active' ? '…' : '—'}</span>
              </div>
            );
          })}
        </div>
      </div>

      <h3>Activity log</h3>
      <div className="rail-card">
        <div className="log" ref={logRef}>
          {(log || []).map((l,i) => (
            <div key={i}>
              <span className="ts">{l.t}</span>
              <span className={l.kind || ''}>{l.msg}</span>
            </div>
          ))}
        </div>
      </div>

      <h3>AI Usage</h3>
      <div className="rail-card" style={{fontSize:11.5, color:'var(--ink-2)', lineHeight:1.55}}>
        {[
          ['Tokens used',  (stats?.tokens||0).toLocaleString()],
          ['Emails per scan', '≤ 20'],
        ].map(([k,v]) => (
          <div key={k} style={{display:'flex', justifyContent:'space-between', color:'var(--ink-3)', marginTop:4}}>
            <span>{k}</span>
            <span style={{fontFamily:'var(--mono)'}}>{v}</span>
          </div>
        ))}
      </div>
    </aside>
  );
}

// ============ Root App ============
function App() {
  const [authStatus,   setAuthStatus]   = useState(null);   // null=loading, false=unauthed, true=authed
  const [authError,    setAuthError]    = useState(null);
  const [appState,     setAppState]     = useState(null);
  const [view,         setView]         = useState('todo');
  const [toasts,       setToasts]       = useState([]);
  const [openTask,     setOpenTask]     = useState(null);
  const [openThread,   setOpenThread]   = useState(null);
  const [banner,       setBanner]       = useState(null);
  const [showRail,     setShowRail]     = useState(true);

  // ---- Auth check on mount ----
  useEffect(() => {
    // Read auth_error from URL if any
    const params = new URLSearchParams(location.search);
    if (params.get('auth_error')) {
      setAuthError(decodeURIComponent(params.get('auth_error')));
      history.replaceState({}, '', '/');
    }

    api.get('/api/auth/status')
      .then(({ authenticated }) => setAuthStatus(authenticated))
      .catch(() => setAuthStatus(false));
  }, []);

  // ---- Poll state when authenticated ----
  useEffect(() => {
    if (!authStatus) return;

    const load = () => {
      api.get('/api/state')
        .then(s => setAppState(s))
        .catch(console.error);
    };

    load();
    const id = setInterval(load, 20000); // refresh every 20 s
    return () => clearInterval(id);
  }, [authStatus]);

  // ---- Helpers ----
  const pushToast = (msg, folder) => {
    const id = Math.random().toString(36).slice(2);
    setToasts(t => [...t, { id, msg, folder }]);
  };
  const removeToast = id => setToasts(t => t.filter(x => x.id !== id));

  const refreshState = useCallback(() => {
    api.get('/api/state').then(s => setAppState(s)).catch(console.error);
  }, []);

  // ---- Scan ----
  const handleScan = async () => {
    if (appState?.scanning) return;
    try {
      await api.post('/api/scan', {});
      pushToast('Scan started — refreshing shortly…');
      setTimeout(refreshState, 4000);
      setTimeout(refreshState, 9000);
    } catch (err) {
      pushToast('Scan failed: ' + err.message);
    }
  };

  // ---- Thread toggle ----
  const handleToggle = (threadId) => {
    setAppState(prev => ({
      ...prev,
      threads: prev.threads.map(t => t.id === threadId ? { ...t, expanded: !t.expanded } : t),
    }));
  };

  // ---- Task done/undo ----
  const handleCheck = async (threadId, taskId) => {
    const thread = appState?.threads?.find(t => t.id === threadId);
    const task   = thread?.tasks?.find(t => t.id === taskId);
    if (!task) return;

    if (task.doneAt) {
      // undo
      await api.post('/api/task/undo', { threadId, taskId }).catch(console.error);
      setAppState(prev => ({
        ...prev,
        threads: prev.threads.map(th => th.id !== threadId ? th : {
          ...th, tasks: th.tasks.map(t => t.id !== taskId ? t : { ...t, doneAt: null }),
        }),
      }));
    } else {
      // optimistic update
      const now = new Date().toISOString();
      setAppState(prev => ({
        ...prev,
        threads: prev.threads.map(th => th.id !== threadId ? th : {
          ...th, tasks: th.tasks.map(t => t.id !== taskId ? t : { ...t, doneAt: now }),
        }),
      }));

      try {
        const { moved, folder } = await api.post('/api/task/done', { threadId, taskId });
        if (moved && folder) pushToast('Email moved in Outlook →', folder);

        // Task 5: auto-dismiss matching follow-ups
        const matchingFU = (appState?.followUps || []).filter(fu =>
          fu.threadId === threadId ||
          (fu.subject && task?.subject && fu.subject.toLowerCase() === task.subject.toLowerCase())
        );
        for (const fu of matchingFU) {
          api.post('/api/followup/dismiss', { id: fu.id }).catch(console.error);
        }

        refreshState();
      } catch (err) {
        // rollback
        setAppState(prev => ({
          ...prev,
          threads: prev.threads.map(th => th.id !== threadId ? th : {
            ...th, tasks: th.tasks.map(t => t.id !== taskId ? t : { ...t, doneAt: null }),
          }),
        }));
        pushToast('Error: ' + err.message);
      }
    }
  };

  // ---- Standalone task done/undo ----
  const handleCheckStandalone = async (taskId) => {
    const task = appState?.standaloneManualTasks?.find(t => t.id === taskId);
    if (!task) return;

    if (task.doneAt) {
      // undo
      setAppState(prev => ({
        ...prev,
        standaloneManualTasks: (prev.standaloneManualTasks || []).map(t =>
          t.id !== taskId ? t : { ...t, doneAt: null }
        ),
      }));
      api.post('/api/task/standalone/undo', { id: taskId }).catch(console.error);
    } else {
      // mark done
      const now = new Date().toISOString();
      setAppState(prev => ({
        ...prev,
        standaloneManualTasks: (prev.standaloneManualTasks || []).map(t =>
          t.id !== taskId ? t : { ...t, doneAt: now }
        ),
      }));
      try {
        await api.post('/api/task/standalone/done', { id: taskId });
        refreshState();
      } catch (err) {
        setAppState(prev => ({
          ...prev,
          standaloneManualTasks: (prev.standaloneManualTasks || []).map(t =>
            t.id !== taskId ? t : { ...t, doneAt: null }
          ),
        }));
        pushToast('Error: ' + err.message);
      }
    }
  };

  // ---- Dispute actions ----
  const handleDispute = async (a) => {
    try {
      if (a.type === 'state') {
        await api.post('/api/dispute/state', { id: a.id, state: a.next });
        if (a.next === 'resolved') pushToast('Email moved in Outlook →', 'Disputes & Claims');
      }
      if (a.type === 'close') {
        await api.post('/api/dispute/close', { id: a.id });
        pushToast('Dispute closed →', 'Disputes & Claims');
      }
      if (a.type === 'delete') {
        await api.post('/api/dispute/delete', { id: a.id });
        pushToast('Dispute deleted · audit kept');
      }
      refreshState();
    } catch (err) {
      pushToast('Error: ' + err.message);
    }
  };

  // ---- Banner ----
  const handleBanner = (choice) => {
    if (choice === 'accept' && banner) {
      pushToast('Added to thread', banner.threadTitle);
      refreshState();
    }
    setBanner(null);
  };

  // ---- Counts ----
  const counts = useMemo(() => {
    const threads  = appState?.threads  || [];
    const disputes = appState?.disputes || [];
    const followup = appState?.followUps || [];
    const done     = appState?.doneHistory || {};

    return {
      todo:        threads.reduce((n,t) => n + t.tasks.filter(x=>!x.doneAt && !x.deletedAt).length, 0),
      done:        Object.values(done).flat().length,
      followup:    followup.length,
      disputes:    disputes.filter(d => d.state !== 'resolved').length,
      disputesEsc: disputes.filter(d => d.state === 'escalated').length,
      deleted:     (
        threads.reduce((n,t) => n + t.tasks.filter(x => x.isManual && x.deletedAt).length, 0) +
        (appState?.standaloneManualTasks||[]).filter(x => x.deletedAt).length +
        (appState?.dismissedFollowUps||[]).length
      ) || undefined,
    };
  }, [appState]);

  // ---- Update page title with badge ----
  useEffect(() => {
    document.title = counts.todo > 0
      ? `(${counts.todo}) ATLAS Email Agent — Elite Roads`
      : 'ATLAS Email Agent — Elite Roads';
  }, [counts.todo]);

  // ---- Loading ----
  if (authStatus === null) {
    return (
      <div className="auth-screen">
        <div className="auth-card" style={{textAlign:'center'}}>
          <I.spin style={{width:28, height:28, color:'var(--ink-3)', margin:'0 auto'}}/>
          <p style={{marginTop:12, color:'var(--ink-3)'}}>Loading…</p>
        </div>
      </div>
    );
  }

  if (authStatus === false) {
    return <AuthScreen error={authError} />;
  }

  if (!appState) {
    return (
      <div className="auth-screen">
        <div className="auth-card" style={{textAlign:'center'}}>
          <I.spin style={{width:28, height:28, color:'var(--ink-3)', margin:'0 auto'}}/>
          <p style={{marginTop:12, color:'var(--ink-3)'}}>Loading state…</p>
        </div>
      </div>
    );
  }

  const currentThread = openTask
    ? appState.threads.find(th => th.tasks.some(x => x.id === openTask.id))
    : null;

  return (
    <div className="app" data-rail={showRail ? 'true' : 'false'} data-density="compact" data-accent="green">
      <Sidebar view={view} setView={setView} counts={counts} employee={appState.employee} />
      <Topbar
        view={view}
        scanning={appState.scanning}
        lastScan={appState.lastScanAt}
        nextScanAt={appState.nextScanAt}
        onScan={handleScan}
      />

      <main className="main">
        {view === 'todo' && (
          <TodoView
            threads={appState.threads || []}
            onCheck={handleCheck}
            onOpenTask={(t, th) => { setOpenTask(t); setOpenThread(th); }}
            banner={banner}
            onBanner={handleBanner}
            onRefresh={refreshState}
            dismissedFollowUps={appState.dismissedFollowUps || []}
            standaloneManualTasks={appState.standaloneManualTasks || []}
            onCheckStandalone={handleCheckStandalone}
          />
        )}
        {view === 'done' && <DoneView doneHistory={appState.doneHistory} onUndo={refreshState} />}
        {view === 'deleted' && <RecentlyDeletedView
          threads={appState.threads || []}
          standaloneManualTasks={appState.standaloneManualTasks || []}
          dismissedFollowUps={appState.dismissedFollowUps || []}
          onRefresh={refreshState}
        />}
        {view === 'followup' && <FollowupsView items={appState.followUps || []} onRefresh={refreshState} />}
        {view === 'disputes' && (
          <DisputesView
            disputes={appState.disputes || []}
            onAction={handleDispute}
            onRefresh={refreshState}
          />
        )}
        {view === 'folders' && <FolderRulesView folderRules={appState.folderRules} onRefresh={refreshState} />}
        {view === 'style' && (
          <ReplyStyleView
            employee={appState.employee}
            onSave={async (rs) => {
              await api.post('/api/settings/reply', rs);
              pushToast('Reply style saved');
              refreshState();
            }}
          />
        )}
      </main>

      {showRail && (
        <ActivityRail
          log={appState.log || []}
          pipelineStep={appState.pipelineStep || 6}
          stats={appState.stats}
        />
      )}

      <ToastHost toasts={toasts} remove={removeToast} />

      {openTask && (currentThread || openThread) && (
        <TaskModal
          task={openTask}
          thread={currentThread || openThread}
          onClose={() => { setOpenTask(null); setOpenThread(null); }}
          onCheck={() => handleCheck((currentThread || openThread).id, openTask.id)}
          onSend={refreshState}
        />
      )}
    </div>
  );
}

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