/* Dispatch — My Tasks (personal QA desk)
 * Loaded by index.html as a <script type="text/babel"> module, after lib.jsx.
 *
 * Replicates the original app's "Your QA Desk" (LiveQaDesk) data pulling on the
 * live cross-lane feed: the signed-in user's active tickets, plus up-for-grabs
 * and a failing watchlist. A "viewing as" picker sets the current user (via
 * DispatchAPI.setCurrentUserLogin) so the desk populates for a chosen person. */

// A titled, sortable, paginated ticket table used for each section of the desk.
// A ticket's "project" category — Help Desk tickets group under "Help Desk"
// (matching their Source badge); GitHub tickets group under their repo, and
// fall back to the lane name only when no repo is known.
const mtProjectOf = (t) =>
  t.source === 'helpdesk' ? 'Help Desk'
    : t.repoName || t.repo || (t.lane ? titleCase(t.lane) : '—');
// Where the ticket came from: the Help Desk (legacy) vs a GitHub-synced repo.
const mtSourceLabel = (t) => t.source === 'helpdesk' ? 'Help Desk' : 'GitHub';

function MtTable({ title, subtitle, rows, empty, onOpen, groupByProject, perPage = PER_PAGE }) {
  const [sort, toggleSort] = useSort(null);
  const [page, setPage] = useState(1);
  const [project, setProject] = useState('all');
  const projects = groupByProject ? [...new Set(rows.map(mtProjectOf))].sort() : [];
  const scoped = groupByProject && project !== 'all' ? rows.filter(t => mtProjectOf(t) === project) : rows;
  const sortVal = (t, k) => k === 'priority' ? (PRIORITY_RANK[t.priority] ?? 9)
    : k === 'assignee' ? String(t.assigneeName || t.assigneeLogin || '')
    : k === 'project' ? mtProjectOf(t)
    : k === 'source' ? mtSourceLabel(t)
    : (t[k] ?? '');
  const sorted = sortRows(scoped, sort, sortVal);
  useEffect(() => { setPage(1); }, [rows.length, sort, project]);
  const pageCount = Math.max(1, Math.ceil(sorted.length / perPage));
  const paged = sorted.slice((page - 1) * perPage, page * perPage);
  const cols = (groupByProject ? 6 : 5) + 1;
  return (
    <Card>
      <div className="flex flex-wrap items-center justify-between gap-2 border-b p-3">
        <span className="flex items-center gap-2 font-semibold">{title}<Badge variant="outline">{rows.length}</Badge></span>
        <div className="flex items-center gap-2">
          {subtitle && <span className="text-xs text-muted-foreground">{subtitle}</span>}
          {groupByProject && projects.length > 0 && (
            <Select className="w-44" value={project} onChange={e => setProject(e.target.value)}>
              <option value="all">All projects ({projects.length})</option>
              {projects.map(p => <option key={p} value={p}>{p}</option>)}
            </Select>
          )}
        </div>
      </div>
      <div className="overflow-x-auto">
        <table className="w-full text-sm">
          <thead className="border-b text-muted-foreground">
            <tr className="[&>th]:px-4 [&>th]:py-2.5 [&>th]:text-left [&>th]:font-medium">
              <SortHeader label="Item" sortKey="title" sort={sort} onSort={toggleSort} />
              <SortHeader label="Source" sortKey="source" sort={sort} onSort={toggleSort} />
              {groupByProject && <SortHeader label="Project" sortKey="project" sort={sort} onSort={toggleSort} />}
              <SortHeader label="Stage" sortKey="qaStage" sort={sort} onSort={toggleSort} />
              <SortHeader label="Priority" sortKey="priority" sort={sort} onSort={toggleSort} />
              <SortHeader label="Assignee" sortKey="assignee" sort={sort} onSort={toggleSort} />
              <SortHeader label="Age" sortKey="age" sort={sort} onSort={toggleSort} align="right" />
            </tr>
          </thead>
          <tbody className="divide-y">
            {sorted.length === 0 && <tr><td colSpan={cols} className="px-4 py-6 text-center text-muted-foreground">{project !== 'all' ? 'No tickets in this project.' : empty}</td></tr>}
            {paged.map(t => (
              <tr key={t.id} onClick={() => onOpen && onOpen(t)} className="cursor-pointer transition-colors hover:bg-muted/50">
                <td className="max-w-[320px] px-4 py-2.5">
                  <div className="truncate font-medium">{t.title}</div>
                  <div className="font-mono text-xs text-muted-foreground">{t.num}</div>
                </td>
                <td className="px-4 py-2.5"><Badge variant={t.source === 'helpdesk' ? 'secondary' : 'outline'}>{mtSourceLabel(t)}</Badge></td>
                {groupByProject && <td className="max-w-[140px] truncate px-4 py-2.5 text-muted-foreground">{mtProjectOf(t)}</td>}
                <td className="px-4 py-2.5"><Badge variant="outline">{titleCase(t.qaStage || t.status)}</Badge></td>
                <td className="px-4 py-2.5"><Badge variant={prioVariant(t.priority)}>{t.priority}</Badge></td>
                <td className="max-w-[150px] truncate px-4 py-2.5 text-muted-foreground">{t.assigneeName || t.assigneeLogin || '—'}</td>
                <td className="px-4 py-2.5 text-right text-muted-foreground">{t.age}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>
      <div className="flex items-center justify-between border-t px-4 py-2 text-xs text-muted-foreground">
        <span>{sorted.length}{scoped.length !== rows.length ? ` of ${rows.length}` : ''} total</span>
        <Pagination page={page} pageCount={pageCount} onPage={setPage} />
      </div>
    </Card>
  );
}

function MyTasks() {
  const [live, setLive] = useState(() => (window.__DISPATCH_LIVE__ && window.__DISPATCH_LIVE__.tickets) || null);
  const [currentLogin, setCurrentLogin] = useState(() => api.getCurrentUserLogin());
  const [overviewOpen, setOverviewOpen] = useOverviewOpen();
  const [openItem, setOpenItem] = useState(null);
  useEffect(() => {
    const readData = () => setLive((window.__DISPATCH_LIVE__ && window.__DISPATCH_LIVE__.tickets) || null);
    const readUser = () => setCurrentLogin(api.getCurrentUserLogin());
    readData();
    window.addEventListener('dispatch:data-loaded', readData);
    window.addEventListener('dispatch:current-user-changed', readUser);
    return () => {
      window.removeEventListener('dispatch:data-loaded', readData);
      window.removeEventListener('dispatch:current-user-changed', readUser);
    };
  }, []);

  // Ignore bot-filed tickets (dependabot, github-actions, etc.) across every
  // list and KPI on this page — see requesterIsBot in the API client.
  const tickets = (Array.isArray(live) ? live : []).filter(t => !t.requesterIsBot);
  const assignees = (window.__DISPATCH_LIVE__ && window.__DISPATCH_LIVE__.allAssignees) || [];
  const me = assignees.find(a => a.githubLogin === currentLogin);
  // GitHub tickets are assigned by login; Help Desk tickets by email — match both.
  const currentEmail = (me?.email || api.getCurrentUserEmail() || '').toLowerCase();
  const assignedToMe = (t) =>
    (currentLogin && t.assigneeLogin === currentLogin) ||
    (currentEmail && (t.assigneeEmail || '').toLowerCase() === currentEmail);
  const anyAssignee = (t) => t.assigneeLogin || t.assigneeEmail;
  // Open = not passed/failed QA, and not a resolved/closed Help Desk ticket.
  const isOpen = (t) => t.qaStage !== 'pass' && t.qaStage !== 'fail' && t.status !== 'resolved' && t.status !== 'closed';

  const openTickets = tickets.filter(isOpen);
  const mine = (currentLogin || currentEmail) ? openTickets.filter(assignedToMe) : [];
  // Up for Grabs pool: unassigned tickets only — anything with an assignee is
  // removed. Not restricted to open; any ticket with no owner qualifies.
  const upForGrabs = tickets.filter(t => !anyAssignee(t));
  const watchlist = (currentLogin || currentEmail)
    ? tickets.filter(t => anyAssignee(t) && !assignedToMe(t) && t.qaStage === 'fail')
    : tickets.filter(t => t.qaStage === 'fail');
  // Recently Resolved: the current user's own closed/resolved/passed tickets
  // (GitHub matched by login, Help Desk by email), newest first.
  const isResolved = (t) => t.qaStage === 'pass' || t.status === 'resolved' || t.status === 'closed';
  const recentlyResolved = (currentLogin || currentEmail)
    ? tickets.filter(t => isResolved(t) && assignedToMe(t)).sort((a, b) => (b.updatedAtMs || 0) - (a.updatedAtMs || 0))
    : [];
  const byStage = mine.reduce((a, t) => { a[t.qaStage] = (a[t.qaStage] || 0) + 1; return a; }, {});

  const firstName = me ? ((me.name || '').split(' ')[0] || me.githubLogin) : '';
  const kpis = [
    { label: 'Assigned to you', value: mine.length },
    { label: 'Closed', value: recentlyResolved.length },
    { label: 'Up for grabs', value: upForGrabs.length },
    { label: 'Total open', value: openTickets.length },
  ];
  function pick(login) { api.setCurrentUserLogin(login); setCurrentLogin(login); }

  return (
    <div className="space-y-4">
      {overviewOpen && (
        <>
          <Card className="border-primary/20 bg-primary/5">
            <CardContent className="pt-6">
              <div className="text-xs font-medium uppercase tracking-wider text-muted-foreground">My Tasks · Live</div>
              <h2 className="mt-1 text-2xl font-semibold tracking-tight">
                {currentLogin ? `Morning${firstName ? ', ' + firstName : ''}. You have ${mine.length} ticket${mine.length === 1 ? '' : 's'} in flight.` : 'Pick yourself to see your queue.'}
              </h2>
              <p className="mt-1 text-sm text-muted-foreground">{byStage.fail || 0} failed, {byStage.progress || 0} mid-test, {byStage.assigned || 0} queued · {watchlist.length} cross-team ticket{watchlist.length === 1 ? '' : 's'} need attention.</p>
              <div className="mt-3 flex items-center gap-2">
                <span className="text-sm text-muted-foreground">Viewing as</span>
                <Select className="w-56" value={currentLogin} onChange={e => pick(e.target.value)}>
                  <option value="">— select user —</option>
                  {assignees.map(a => <option key={a.githubLogin || a.id} value={a.githubLogin}>{a.name || a.githubLogin}</option>)}
                </Select>
              </div>
            </CardContent>
          </Card>
          <div className="grid gap-4 sm:grid-cols-2 lg:grid-cols-4">
            {kpis.map(k => (
              <Card key={k.label}><CardContent className="pt-5">
                <div className="text-sm text-muted-foreground">{k.label}</div>
                <div className="mt-1 text-3xl font-semibold tracking-tight">{k.value}</div>
              </CardContent></Card>
            ))}
          </div>
        </>
      )}

      <MtTable title="Your Active Tickets" rows={mine} onOpen={setOpenItem} perPage={3}
        empty={currentLogin ? 'Nothing assigned to you — grab one from Up for Grabs.' : 'Pick yourself in the header to see your queue.'} />
      <div className="grid gap-4 lg:grid-cols-2">
        <MtTable title="Up for Grabs" subtitle="unassigned" rows={upForGrabs} empty="Nothing unassigned right now." onOpen={setOpenItem} groupByProject />
        <MtTable title="Recently Resolved" subtitle="closed · assigned to you" rows={recentlyResolved} empty={currentLogin ? 'Nothing resolved recently.' : 'Pick yourself to see your resolved tickets.'} onOpen={setOpenItem} />
      </div>
      {openItem && <TicketDetailModal item={openItem} onClose={() => setOpenItem(null)} />}
    </div>
  );
}
