/* global React, Icon, Avatar, Badge, PageHeader, SectionHead, MEMBERS, apiGet, apiPost, activeMembers */
const { useState: usePresoState, useEffect: usePresoEffect, useMemo: usePresoMemo } = React;

// === News-segment presentation order ========================================
// Admin page that manages the rotation of news-segment presenter teams (2-3 people).
// Build a random rotation from the roster, hand-edit order + membership, mark teams
// presented, and fire reminders (morning-of / pre-presentation) to the upcoming team.
// Backed by /api/presentations*. See tasks/news-segment-presentation-order.md.
// `embedded` renders the feature without its own PageHeader (the host page supplies
// one) — used to host these features inside the Notify page. Standalone otherwise.
function PresentationOrder({ members = MEMBERS, currentUser, viewMode = 'member', embedded = false }) {
  const isAdminView = Boolean(currentUser?.isAdmin && viewMode === 'admin');

  const [rotation, setRotation] = usePresoState({ teams: [], nextTeamId: null });
  const [status, setStatus] = usePresoState('loading'); // loading | ready | error
  const [error, setError] = usePresoState('');
  const [flash, setFlash] = usePresoState(''); // transient success line
  const [busy, setBusy] = usePresoState(false);
  const [mode, setMode] = usePresoState('view'); // view | build | edit
  const [selection, setSelection] = usePresoState(() => new Set()); // build: chosen member ids
  const [draftTeams, setDraftTeams] = usePresoState([]); // edit: [{ id, memberIds }]

  const roster = usePresoMemo(() => activeMembers(members).slice().sort((a, b) => a.name.localeCompare(b.name)), [members]);
  const memberById = usePresoMemo(() => new Map(roster.map((m) => [m.id, m])), [roster]);

  usePresoEffect(() => {
    let cancelled = false;
    apiGet('/api/presentations')
      .then((data) => { if (!cancelled) { setRotation(normalizeRotation(data)); setStatus('ready'); } })
      .catch((err) => { if (!cancelled) { setError(err.message || 'Could not load the rotation.'); setStatus('error'); } });
    return () => { cancelled = true; };
  }, []);

  function note(message) {
    setFlash(message);
    setTimeout(() => setFlash(''), 3200);
  }

  // --- view-mode actions ---------------------------------------------------
  async function togglePresented(team) {
    setBusy(true); setError('');
    try {
      const data = await apiPost(`/api/presentations/${team.id}/presented`, { presented: !team.presented });
      setRotation(normalizeRotation(data));
      if (data.notifiedNext && data.notifiedNext.recipientCount) {
        const nextTeam = (data.teams || []).find((t) => t.id === data.notifiedNext.teamId);
        const who = nextTeam && nextTeam.members.length
          ? nextTeam.members.map((m) => m.name.split(' ')[0]).join(', ')
          : 'the next team';
        note(`Marked done — pinged ${who} on Slack that they're up next.`);
      }
    } catch (err) {
      setError(err.message || 'Could not update the team.');
    } finally { setBusy(false); }
  }

  async function remind(team, when) {
    setBusy(true); setError('');
    try {
      const data = await apiPost(`/api/presentations/${team.id}/remind`, { when });
      const who = team.members.length === 1 ? '1 presenter' : `${data.recipientCount ?? team.members.length} presenters`;
      note(`${when === 'morning' ? 'Morning-of' : 'Pre-presentation'} reminder sent to ${who}.`);
    } catch (err) {
      setError(err.message || 'Could not send the reminder.');
    } finally { setBusy(false); }
  }

  // --- build mode (generate a fresh random rotation) -----------------------
  function startBuild() {
    setError('');
    // Pre-select whoever is already in the current rotation, else the whole roster.
    const inRotation = new Set(rotation.teams.flatMap((t) => t.members.map((m) => m.id)));
    setSelection(inRotation.size ? inRotation : new Set(roster.map((m) => m.id)));
    setMode('build');
  }
  function toggleSelected(id) {
    setSelection((current) => {
      const next = new Set(current);
      if (next.has(id)) next.delete(id); else next.add(id);
      return next;
    });
  }
  async function generate() {
    setBusy(true); setError('');
    try {
      const data = await apiPost('/api/presentations/generate', { memberIds: [...selection] });
      setRotation(normalizeRotation(data));
      setMode('view');
      note('Built a fresh randomized rotation.');
    } catch (err) {
      setError(err.message || 'Could not build the rotation.');
    } finally { setBusy(false); }
  }

  // --- edit mode (reorder / edit membership) -------------------------------
  function startEdit() {
    setError('');
    setDraftTeams(rotation.teams.map((t) => ({ id: t.id, memberIds: t.members.map((m) => m.id) })));
    setMode('edit');
  }
  const assignedInDraft = usePresoMemo(
    () => new Set(draftTeams.flatMap((t) => t.memberIds)),
    [draftTeams]
  );
  const unassigned = roster.filter((m) => !assignedInDraft.has(m.id));

  function moveTeam(index, delta) {
    setDraftTeams((teams) => {
      const next = teams.slice();
      const target = index + delta;
      if (target < 0 || target >= next.length) return teams;
      [next[index], next[target]] = [next[target], next[index]];
      return next;
    });
  }
  function removeTeam(index) {
    setDraftTeams((teams) => teams.filter((_, i) => i !== index));
  }
  function addTeam() {
    setDraftTeams((teams) => [...teams, { id: `new-${teams.length}`, memberIds: [] }]);
  }
  function removeFromTeam(index, memberId) {
    setDraftTeams((teams) => teams.map((t, i) => (i === index ? { ...t, memberIds: t.memberIds.filter((id) => id !== memberId) } : t)));
  }
  function addToTeam(index, memberId) {
    if (!memberId) return;
    setDraftTeams((teams) => teams.map((t, i) => (i === index ? { ...t, memberIds: [...t.memberIds, memberId] } : t)));
  }
  async function saveEdit() {
    setBusy(true); setError('');
    try {
      const teams = draftTeams.map((t) => ({ memberIds: t.memberIds })).filter((t) => t.memberIds.length > 0);
      const data = await apiPost('/api/presentations', { teams });
      setRotation(normalizeRotation(data));
      setMode('view');
      note('Saved the presentation order.');
    } catch (err) {
      setError(err.message || 'Could not save the order.');
    } finally { setBusy(false); }
  }

  if (!isAdminView) {
    const guard = (
      <div className="card" style={{ padding: 22 }}>
        <div className="muted">Switch to admin view to manage the news-segment presentation order.</div>
      </div>
    );
    return embedded ? guard : (
      <div>
        <PageHeader eyebrow="Operations" title="News segments"/>
        {guard}
      </div>
    );
  }

  const actions = mode === 'view' ? (
    <>
      <button type="button" className="btn btn-ghost btn-sm" onClick={startEdit} disabled={busy || !rotation.teams.length}>
        <Icon name="edit" size={14}/> Edit order
      </button>
      <button type="button" className="btn btn-primary btn-sm" onClick={startBuild} disabled={busy}>
        <Icon name="shuffle" size={14}/> {rotation.teams.length ? 'Re-shuffle' : 'Build rotation'}
      </button>
    </>
  ) : null;

  const content = (
    <>
      {error && <div className="form-error" style={{ marginBottom: 14 }}>{error}</div>}
      {flash && (
        <div className="card" style={{ padding: '10px 14px', marginBottom: 14, display: 'flex', gap: 8, alignItems: 'center', borderLeft: '3px solid var(--coral-500)' }}>
          <Icon name="check" size={14}/> <span style={{ fontSize: 13 }}>{flash}</span>
        </div>
      )}

      {status === 'loading' && <div className="card muted" style={{ padding: 20 }}>Loading rotation…</div>}

      {status === 'ready' && mode === 'view' && (
        <RotationView
          rotation={rotation}
          busy={busy}
          onTogglePresented={togglePresented}
          onRemind={remind}
          onBuild={startBuild}/>
      )}

      {status === 'ready' && mode === 'build' && (
        <BuildPanel
          roster={roster}
          selection={selection}
          onToggle={toggleSelected}
          onSelectAll={() => setSelection(new Set(roster.map((m) => m.id)))}
          onClear={() => setSelection(new Set())}
          onCancel={() => setMode('view')}
          onGenerate={generate}
          busy={busy}/>
      )}

      {status === 'ready' && mode === 'edit' && (
        <EditPanel
          draftTeams={draftTeams}
          memberById={memberById}
          unassigned={unassigned}
          onMove={moveTeam}
          onRemoveTeam={removeTeam}
          onAddTeam={addTeam}
          onRemoveMember={removeFromTeam}
          onAddMember={addToTeam}
          onCancel={() => setMode('view')}
          onSave={saveEdit}
          busy={busy}/>
      )}
    </>
  );

  if (embedded) {
    return (
      <div>
        {actions && (
          <div className="row" style={{ justifyContent: 'flex-end', gap: 8, marginBottom: 14 }}>{actions}</div>
        )}
        {content}
      </div>
    );
  }

  return (
    <div>
      <PageHeader
        eyebrow="Operations"
        title="News segments"
        sub="Set the order in which presenter teams (2–3 people) give the news segment, and remind whoever's up next."
        actions={actions}/>
      {content}
    </div>
  );
}

// Read-only rotation: ordered team cards, "Next up" highlight, presented toggle,
// and the two reminder buttons.
function RotationView({ rotation, busy, onTogglePresented, onRemind, onBuild }) {
  if (!rotation.teams.length) {
    return (
      <div className="card" style={{ padding: 26, textAlign: 'center' }}>
        <div style={{ fontWeight: 600, color: 'var(--steel-900)', marginBottom: 4 }}>No rotation yet</div>
        <div className="muted" style={{ fontSize: 13, marginBottom: 16 }}>
          Build a randomized order of presenter teams from the roster to get started.
        </div>
        <button type="button" className="btn btn-primary btn-sm" onClick={onBuild} disabled={busy}>
          <Icon name="shuffle" size={14}/> Build rotation
        </button>
      </div>
    );
  }

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      {rotation.teams.map((team, index) => {
        const isNext = team.id === rotation.nextTeamId;
        return (
          <div key={team.id} className="card" style={{
            padding: 16,
            opacity: team.presented ? 0.6 : 1,
            borderLeft: isNext ? '3px solid var(--coral-500)' : '3px solid transparent',
          }}>
            <div className="row between" style={{ alignItems: 'flex-start', gap: 14 }}>
              <div className="row" style={{ gap: 14, alignItems: 'center', flex: 1, minWidth: 0 }}>
                <div className="mono" style={{
                  fontSize: 18, fontWeight: 700, width: 30, textAlign: 'center',
                  color: isNext ? 'var(--coral-600)' : 'var(--steel-400)', flexShrink: 0,
                }}>{index + 1}</div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div className="row" style={{ gap: 8, alignItems: 'center', marginBottom: 4, flexWrap: 'wrap' }}>
                    {team.members.map((m) => (
                      <span key={m.id} className="row" style={{ gap: 6, alignItems: 'center' }}>
                        <Avatar initials={m.initials} size={24}/>
                        <span style={{ fontSize: 13.5, fontWeight: 500 }}>{m.name}</span>
                      </span>
                    ))}
                  </div>
                  <div className="row" style={{ gap: 8 }}>
                    {isNext && <Badge tone="coral" dot>Next up</Badge>}
                    {team.presented && <Badge tone="cream">Presented</Badge>}
                  </div>
                </div>
              </div>
              <div className="row preso-actions" style={{ gap: 6, flexWrap: 'wrap', justifyContent: 'flex-end' }}>
                <button type="button" className="btn btn-ghost btn-sm" disabled={busy}
                  title="Remind the morning of their meeting" onClick={() => onRemind(team, 'morning')}>
                  <Icon name="bell" size={13}/> Morning-of
                </button>
                <button type="button" className="btn btn-ghost btn-sm" disabled={busy}
                  title="Remind right before they present" onClick={() => onRemind(team, 'pre')}>
                  <Icon name="bell" size={13}/> On deck
                </button>
                <button type="button" className={`btn btn-sm ${team.presented ? 'btn-ghost' : 'btn-secondary'}`} disabled={busy}
                  onClick={() => onTogglePresented(team)}>
                  <Icon name={team.presented ? 'rotate-ccw' : 'check'} size={13}/>
                  {team.presented ? ' Undo' : ' Mark done'}
                </button>
              </div>
            </div>
          </div>
        );
      })}
    </div>
  );
}

// Member picker → generate a fresh randomized rotation.
function BuildPanel({ roster, selection, onToggle, onSelectAll, onClear, onCancel, onGenerate, busy }) {
  return (
    <div className="card" style={{ padding: 18 }}>
      <SectionHead
        title="Build a rotation"
        meta={`${selection.size} of ${roster.length} selected`}
        action={(
          <div className="row" style={{ gap: 8 }}>
            <button type="button" className="btn btn-ghost btn-sm" onClick={onSelectAll}>Select all</button>
            <button type="button" className="btn btn-ghost btn-sm" onClick={onClear}>Clear</button>
          </div>
        )}/>
      <div className="muted" style={{ fontSize: 12.5, margin: '4px 0 14px' }}>
        Pick who's presenting. They'll be shuffled into teams of 2–3 in a random order. You can edit the result afterward.
      </div>
      <div className="preso-roster-grid">
        {roster.map((m) => {
          const checked = selection.has(m.id);
          return (
            <label key={m.id} className="row" style={{
              gap: 9, alignItems: 'center', padding: '7px 10px', cursor: 'pointer',
              border: '1px solid var(--border-default)', borderRadius: 8,
              background: checked ? 'var(--coral-50, var(--cream-100))' : 'transparent',
            }}>
              <input type="checkbox" checked={checked} onChange={() => onToggle(m.id)}/>
              <Avatar initials={m.initials} size={24}/>
              <span style={{ fontSize: 13, minWidth: 0, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{m.name}</span>
            </label>
          );
        })}
      </div>
      <div className="row" style={{ justifyContent: 'flex-end', gap: 8 }}>
        <button type="button" className="btn btn-ghost" onClick={onCancel} disabled={busy}>Cancel</button>
        <button type="button" className="btn btn-primary" onClick={onGenerate} disabled={busy || selection.size < 2}>
          <Icon name="shuffle" size={14}/> {busy ? 'Shuffling…' : 'Shuffle into teams'}
        </button>
      </div>
    </div>
  );
}

// Reorder teams, edit membership, add/remove teams.
function EditPanel({ draftTeams, memberById, unassigned, onMove, onRemoveTeam, onAddTeam, onRemoveMember, onAddMember, onCancel, onSave, busy }) {
  return (
    <div className="card" style={{ padding: 18 }}>
      <SectionHead title="Edit order" meta="Reorder teams and adjust who's on each"/>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 10, margin: '12px 0 16px' }}>
        {draftTeams.map((team, index) => {
          const oversized = team.memberIds.length > 3;
          return (
            <div key={team.id} style={{ border: '1px solid var(--border-default)', borderRadius: 10, padding: 12 }}>
              <div className="row between" style={{ alignItems: 'flex-start', gap: 12 }}>
                <div className="row" style={{ gap: 6, alignItems: 'center' }}>
                  <div style={{ display: 'flex', flexDirection: 'column', gap: 2 }}>
                    <button type="button" className="btn btn-ghost btn-sm" style={{ padding: 2 }}
                      onClick={() => onMove(index, -1)} disabled={index === 0} aria-label="Move up">
                      <Icon name="chevron-up" size={14}/>
                    </button>
                    <button type="button" className="btn btn-ghost btn-sm" style={{ padding: 2 }}
                      onClick={() => onMove(index, 1)} disabled={index === draftTeams.length - 1} aria-label="Move down">
                      <Icon name="chevron-down" size={14}/>
                    </button>
                  </div>
                  <div className="mono" style={{ fontSize: 16, fontWeight: 700, color: 'var(--steel-400)', width: 22, textAlign: 'center' }}>{index + 1}</div>
                </div>
                <div style={{ flex: 1, minWidth: 0 }}>
                  <div className="row" style={{ gap: 6, flexWrap: 'wrap' }}>
                    {team.memberIds.length === 0 && <span className="muted" style={{ fontSize: 12.5 }}>No members yet</span>}
                    {team.memberIds.map((id) => {
                      const m = memberById.get(id);
                      return (
                        <span key={id} className="row" style={{
                          gap: 6, alignItems: 'center', padding: '4px 6px 4px 4px',
                          border: '1px solid var(--border-default)', borderRadius: 20, fontSize: 12.5,
                        }}>
                          <Avatar initials={m ? m.initials : '?'} size={20}/>
                          {m ? m.name : 'Unknown'}
                          <button type="button" onClick={() => onRemoveMember(index, id)} aria-label="Remove"
                            style={{ border: 'none', background: 'none', cursor: 'pointer', display: 'inline-flex', padding: 0, color: 'inherit' }}>
                            <Icon name="x" size={12}/>
                          </button>
                        </span>
                      );
                    })}
                  </div>
                  <div className="row" style={{ gap: 8, marginTop: 8, alignItems: 'center' }}>
                    <select value="" onChange={(e) => onAddMember(index, e.target.value)}
                      className="preso-add-select"
                      disabled={unassigned.length === 0}>
                      <option value="">{unassigned.length ? '+ Add member…' : 'Everyone assigned'}</option>
                      {unassigned.map((m) => <option key={m.id} value={m.id}>{m.name}</option>)}
                    </select>
                    {oversized && <span className="muted" style={{ fontSize: 11.5, color: 'var(--coral-600)' }}>Teams are usually 2–3</span>}
                  </div>
                </div>
                <button type="button" className="btn btn-ghost btn-sm" onClick={() => onRemoveTeam(index)} aria-label="Remove team" style={{ flexShrink: 0 }}>
                  <Icon name="trash" size={14}/>
                </button>
              </div>
            </div>
          );
        })}
      </div>
      <div className="row between">
        <button type="button" className="btn btn-ghost btn-sm" onClick={onAddTeam}>
          <Icon name="plus" size={13}/> Add team
        </button>
        <div className="row" style={{ gap: 8 }}>
          <button type="button" className="btn btn-ghost" onClick={onCancel} disabled={busy}>Cancel</button>
          <button type="button" className="btn btn-primary" onClick={onSave} disabled={busy}>
            <Icon name="check" size={14}/> {busy ? 'Saving…' : 'Save order'}
          </button>
        </div>
      </div>
    </div>
  );
}

// Defensive normalization — the server already shapes this, but guards against a
// partial/old payload so the page never crashes on render.
function normalizeRotation(data) {
  const teams = Array.isArray(data?.teams) ? data.teams.map((t) => ({
    id: t.id,
    presented: Boolean(t.presented),
    members: Array.isArray(t.members) ? t.members : [],
  })) : [];
  return { teams, nextTeamId: data?.nextTeamId || null };
}

window.PresentationOrder = PresentationOrder;
