/* Import and export — every job that has brought data in or sent it out, and the
   review an import needs when rows cannot be placed.
   Commit model: INSTANT. Accepting or rejecting a row writes into the fixture
   immediately, so the job's own accepted and rejected counts move with the
   decision; starting an import is a staged dialog.

   One data state per screen (§1.1): this screen is EITHER the job list OR the
   review of one job — never both at once. */
(() => {
  const {
    Button, Badge, Tabs, TabsList, TabsTab, Alert, AlertTitle, AlertDescription,
    Table, TableHeader, TableBody, TableRow, TableHead, TableCell,
  } = window.OriginDesignSystem_7c998b;

  function ReviewState({ data, now, viewer, job, onCloseReview, onRowDecision, onAcceptMatched, onPostNote, onReactToNote }) {
    const rows = data.transferRows[job.id] || [];
    const matched = rows.filter((r) => r.detail.indexOf("Matches") === 0);
    const notes = commentsFor(data.comments, "transfer", job.id);
    return (
      <>
        <PageHeader path="/data" title={job.label}
          sub={"Reviewing the rows this import could not place · " + labelOf(IMPORT_SOURCES, job.source) + " · " + job.fileName}
          actions={<Button variant="outline" size="sm" onClick={onCloseReview}><Icon name="arrow-left" />Back to all jobs</Button>} />

        <Figures three items={[
          { label: "Rows in the file", value: formatCount(job.rows), qualifier: formatCount(job.accepted) + " already written into the patient index" },
          { label: "Rows still to decide", value: rows.length, qualifier: matched.length + " of them match an existing patient on name and date of birth" },
          { label: "Rows rejected", value: job.rejected, qualifier: "rejected rows are kept in the file and never written into the index" },
        ]} />

        <Band flush title={"Rows to decide (" + rows.length + ")"}
          note="Accepting writes the row into the patient index against the record it matches. Rejecting leaves it in the file."
          actions={matched.length ? <Button size="sm" onClick={() => onAcceptMatched(job, matched)}>Accept {matched.length} matched rows</Button> : null}>
          {rows.length ? (
            <TableWrap>
              <Table>
                <TableHeader>
                  <TableRow>
                    <TableHead className="hd-num">Line</TableHead>
                    <TableHead>Name in the file</TableHead>
                    <TableHead>Why it stopped</TableHead>
                    <TableHead>What we know</TableHead>
                    <TableHead>Decision</TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {rows.map((row) => (
                    <TableRow key={row.line}>
                      <TableCell className="hd-num">{row.line}</TableCell>
                      <TableCell>{row.name === "Unknown" ? <span className="hd-muted">Unknown</span> : row.name}</TableCell>
                      <TableCell><Badge size="sm" variant="warning">{row.problem}</Badge></TableCell>
                      <TableCell>{row.detail}</TableCell>
                      <TableCell>
                        <span className="hd-actions__row">
                          <Button size="sm" disabled={row.detail.indexOf("Matches") !== 0}
                            onClick={() => onRowDecision(job, row, "accept")}>Accept</Button>
                          <Button size="sm" variant="outline" onClick={() => onRowDecision(job, row, "reject")}>Reject</Button>
                        </span>
                      </TableCell>
                    </TableRow>
                  ))}
                </TableBody>
              </Table>
            </TableWrap>
          ) : (
            <p className="hd-footnote" style={{ paddingInline: "var(--gutter-page)" }}>
              Every row has been decided. {formatCount(job.accepted)} of {formatCount(job.rows)} rows are in the patient index and {job.rejected} were rejected.
            </p>
          )}
        </Band>

        <Band title={"Notes (" + notes.length + ")"} note="Written on this job. Posting is immediate.">
          <NoteThread comments={notes} staff={data.staff} viewer={viewer} now={now}
            onReact={onReactToNote} onPost={(body) => onPostNote({ type: "transfer", id: job.id }, body)}
            placeholder="What you decided about these rows, and why…" />
        </Band>
      </>
    );
  }

  function DataScreen({ data, now, viewer, reviewingId, onReview, onCloseReview, onTransferTransition, onImport, onExport, onRowDecision, onAcceptMatched, onPostNote, onReactToNote }) {
    const [kind, setKind] = React.useState("all");
    const [query, setQuery] = React.useState("");
    const { sort, onSort } = useSort("started", "desc");

    const reviewing = reviewingId ? data.transfers.find((t) => t.id === reviewingId) : null;
    if (reviewing) {
      return <ReviewState data={data} now={now} viewer={viewer} job={reviewing} onCloseReview={onCloseReview}
        onRowDecision={onRowDecision} onAcceptMatched={onAcceptMatched} onPostNote={onPostNote} onReactToNote={onReactToNote} />;
    }

    const needsReview = transfersNeedingReview(data.transfers);
    const toDecide = needsReview.reduce((n, t) => n + (t.pending || 0), 0);
    const failed = failedTransfers(data.transfers);
    const dirty = !!query || kind !== "all";
    const clear = () => { setQuery(""); setKind("all"); };
    const filtered = data.transfers.filter((job) => {
      if (kind !== "all" && job.kind !== kind) return false;
      if (query && (job.label + " " + job.scope + " " + job.fileName).toLowerCase().indexOf(query.toLowerCase()) < 0) return false;
      return true;
    });
    const rows = sortRows(filtered, sort, {
      started: (t) => t.startedAt,
      label: (t) => t.label,
      rows: (t) => t.rows,
    });

    return (
      <>
        <PageHeader
          path="/data"
          title="Import and export"
          sub={"Every job that has brought data into " + HD_HOSPITAL.short + " or sent it out. Exports are kept for " + HD_HOSPITAL.retentionYears + " years."}
          actions={
            <>
              <ImportButton viewer={viewer} onImport={onImport} />
              <ExportMenu scope="This job history" onExport={(format) => onExport("Transfer history", "Every import and export job", data.transfers.length, format)} />
            </>
          }
        />
        <Figures items={[
          { label: "Rows brought in", value: formatCount(rowsAccepted(data.transfers)), qualifier: "written into the index across " + imports(data.transfers).length + " imports" },
          { label: "Rows to review", value: toDecide, qualifier: needsReview.length + (needsReview.length === 1 ? " import is waiting on a decision" : " imports are waiting on a decision") },
          { label: "Exports run", value: exports_(data.transfers).length, qualifier: formatCount(exports_(data.transfers).reduce((n, t) => n + t.rows, 0)) + " rows sent out in total" },
          { label: "Jobs that failed", value: failed.length, qualifier: failed.length ? "nothing was written by them" : "every job finished" },
        ]} />

        {failed.length ? (
          <div className="hd-alertwrap">
            <Alert variant="error">
              <AlertTitle>{failed.length === 1 ? failed[0].label + " failed" : failed.length + " jobs failed"}</AlertTitle>
              <AlertDescription>{failed.map((t) => t.failure).join(" · ")}</AlertDescription>
            </Alert>
          </div>
        ) : null}

        <Band flush title={"Jobs (" + data.transfers.length + ")"} note={kind === "all" ? "Imports and exports together, newest first." : kind === "import" ? "Imports only." : "Exports only."}>
          <div style={{ padding: "0 var(--gutter-page) var(--space-3)" }}>
            <Tabs value={kind} onValueChange={setKind}>
              <TabsList>
                <TabsTab value="all" size="sm">All ({data.transfers.length})</TabsTab>
                <TabsTab value="import" size="sm">Imports ({imports(data.transfers).length})</TabsTab>
                <TabsTab value="export" size="sm">Exports ({exports_(data.transfers).length})</TabsTab>
              </TabsList>
            </Tabs>
          </div>
          <FilterBar query={query} onQuery={setQuery} placeholder="Search job, scope or file name…" dirty={dirty} onClear={clear} selects={[]} />
          {rows.length === 0 ? <NoResults noun="jobs" onClear={clear} /> : (
            <>
              <TableWrap>
                <Table>
                  <TableHeader>
                    <TableRow>
                      <TableHead><SortHead label="Job" sortKey="label" sort={sort} onSort={onSort} /></TableHead>
                      <TableHead>Direction</TableHead>
                      <TableHead>Status</TableHead>
                      <TableHead className="hd-num"><SortHead label="Rows" sortKey="rows" sort={sort} onSort={onSort} /></TableHead>
                      <TableHead>Accepted / rejected</TableHead>
                      <TableHead><SortHead label="Started" sortKey="started" sort={sort} onSort={onSort} /></TableHead>
                      <TableHead>Run by</TableHead>
                      <TableHead>Action</TableHead>
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {rows.map((job) => (
                      <TableRow key={job.id}>
                        <TableCell>
                          <span className="hd-person__text">
                            <span className="hd-person__name">{job.label}</span>
                            <span className="hd-person__meta">{job.scope} · {job.fileName}</span>
                          </span>
                        </TableCell>
                        <TableCell>{labelOf(TRANSFER_KINDS, job.kind)} · {job.format}</TableCell>
                        <TableCell><StatusBadge values={TRANSFER_STATUS} value={job.status} /></TableCell>
                        <TableCell className="hd-num">{formatCount(job.rows)}</TableCell>
                        <TableCell>
                          {formatCount(job.accepted)} accepted
                          {job.pending ? <span className="hd-warn"> · {job.pending} to decide</span> : null}
                          {job.rejected ? <span className="hd-muted"> · {job.rejected} rejected</span> : null}
                        </TableCell>
                        <TableCell><Clock at={job.startedAt} now={now} /></TableCell>
                        <TableCell>{staffName(data.staff, job.byId)}</TableCell>
                        <TableCell>
                          <RowActions transitions={transferTransitions(job)} label={"Actions for " + job.label}
                            onRun={(t) => (t.id === "review_rows" ? onReview(job.id) : onTransferTransition(job, t))} />
                        </TableCell>
                      </TableRow>
                    ))}
                  </TableBody>
                </Table>
              </TableWrap>
              <TableFoot shown={rows.length} total={data.transfers.length} noun="jobs" />
            </>
          )}
        </Band>
      </>
    );
  }

  Object.assign(window, { DataScreen });
})();
