/* Broadcasts — the one-off sends.
   Commit model: INSTANT. Approve, send back, cancel a schedule and retry all
   apply immediately and raise an undo toast; stopping a send in flight is
   irreversible and opens a confirm dialog. Writing a new broadcast needs four
   fields, so this instant screen opens one staged dialog.
   Data state: one branch — populated, or the no-results branch when the filters
   match nothing.
   Scope: the period control sits above the figure row and moves the figures and
   the chart. The filter bar below narrows the table only, and the figures do not
   move with it (§5.3).
   Recession (§5.4): a row with no transition left — a broadcast that has already
   sent — is recessed rather than disabled. It keeps its numbers and its clock. */
(() => {
  const {
    Table, TableHeader, TableBody, TableRow, TableHead, TableCell,
    Select, Button, Checkbox, Badge,
    Empty, EmptyHeader, EmptyMedia, EmptyTitle, EmptyDescription, EmptyContent,
  } = window.OriginDesignSystem_7c998b;

  function BroadcastsScreen({ data, now, period, onPeriodChange, viewer, onNavigate, onBroadcastTransition, onBulkApprove, onNewBroadcast, pushToast }) {
    const [query, setQuery] = React.useState("");
    const [status, setStatus] = React.useState("all");
    const [audience, setAudience] = React.useState("all");
    const [selected, setSelected] = React.useState([]);
    const { sort, onSort } = useSort("clock");

    const days = Number(period);
    const series = deliverySeries(data, days, now);
    const inPeriod = sentBroadcasts(data.broadcasts, days, now);
    const delivered = sumBy(inPeriod, "delivered");
    const opened = sumBy(inPeriod, "opened");
    const clicked = sumBy(inPeriod, "clicked");
    const unsubs = sumBy(inPeriod, "unsubs");
    const partial = inPeriod.filter(BROADCAST_FLAGS.isPartial);
    const inFlight = inPeriod.filter((b) => b.status === "sending");

    const filtered = data.broadcasts.filter((b) => {
      if (query && (b.id + " " + b.name).toLowerCase().indexOf(query.toLowerCase()) === -1) return false;
      if (status !== "all" && b.status !== status) return false;
      if (audience !== "all" && b.audienceId !== audience) return false;
      return true;
    });
    const dirty = query !== "" || status !== "all" || audience !== "all";
    const rows = sortRows(filtered, sort, {
      name: (b) => b.name,
      recipients: (b) => broadcastRecipients(b, data.audiences).count,
      open: (b) => broadcastOpenRate(b),
      clock: (b) => broadcastClock(b),
    });
    const clear = () => { setQuery(""); setStatus("all"); setAudience("all"); };
    const toggle = (id) => setSelected((l) => (l.indexOf(id) > -1 ? l.filter((x) => x !== id) : l.concat([id])));
    const allPicked = filtered.length > 0 && filtered.every((b) => selected.indexOf(b.id) > -1);
    const picked = data.broadcasts.filter((b) => selected.indexOf(b.id) > -1);
    const pickedApprovable = picked.filter((b) => BROADCAST_FLAGS.isApprovableBy(b, viewer));

    const chartDays = series.map((entry) => ({
      at: entry.at,
      total: entry.broadcast.delivered,
      segments: [{ key: "delivered", value: entry.broadcast.delivered }],
      tip: [
        { label: "Delivered", value: formatCount(entry.broadcast.delivered) },
        { label: "Opens", value: formatCount(entry.broadcast.opened) },
        { label: "Clicks", value: formatCount(entry.broadcast.clicked) },
      ].concat(entry.broadcasts.map((b) => ({ label: b.name, value: formatCount(b.delivered) }))),
    }));

    return (
      <>
        <PageHeader
          path="/broadcasts"
          title="Broadcasts"
          actions={
            <>
              <ExportMenu scope={"All " + data.broadcasts.length + " broadcasts"} onExport={(format) => pushToast({ title: "Export started", description: data.broadcasts.length + " broadcasts · " + format })} />
              <Button size="sm" onClick={onNewBroadcast}><Icon name="plus" />New broadcast</Button>
            </>
          }
        />

        <div className="md-scope">
          <span className="md-scope__control">
            <span className="md-scope__label">Period</span>
            <span className="md-scope__select">
              <Select size="sm" items={PERIODS} value={period} aria-label="Period for the figures and the chart" onValueChange={onPeriodChange} />
            </span>
          </span>
          <p className="md-scope__note">
            The figures and the chart cover the {inPeriod.length} broadcasts that went out in the last {days} days. The table below lists every broadcast, whenever it sent.
          </p>
        </div>

        <Figures items={[
          {
            label: "Delivered",
            value: formatCount(delivered),
            qualifier: [
              partial.length
                ? formatCount(sumBy(partial, "sends") - sumBy(partial, "delivered")) + " more never arrived, across " + partial.length + (partial.length === 1 ? " send that failed part-way" : " sends that failed part-way")
                : "Every settled message was handed off",
              inFlight.length ? inFlight.length + (inFlight.length === 1 ? " send is still going out" : " sends are still going out") : null,
            ].filter(Boolean).join(" · "),
          },
          {
            label: "Open rate",
            value: formatPercent(rate(opened, delivered)),
            qualifier: formatCount(opened) + " opens across " + formatCount(delivered) + " delivered",
          },
          {
            label: "Click rate",
            value: formatPercent(rate(clicked, delivered)),
            qualifier: formatCount(clicked) + " clicks across the same " + formatCount(delivered),
          },
          {
            label: "Unsubscribes",
            value: formatCount(unsubs),
            qualifier: formatPercent(rate(unsubs, delivered)) + " of what was delivered",
          },
        ]} />

        <Band title="Broadcast delivery a day" note="One bar a day. Journey sending is on the Overview — this counts broadcasts only.">
          <DayChart
            days={chartDays}
            label={"Broadcast delivery a day over the last " + days + " days"}
            foot={inPeriod.length + " send days in " + days + "; the rest are empty because no broadcast went out."}
          />
        </Band>

        <section className="md-band md-band--flush">
          <div className="md-band__head">
            <div>
              <h2 className="md-band__title">Every broadcast</h2>
              <p className="md-band__note">Newest first. The action column carries the one transition the broadcast's status allows; an unsent broadcast shows its audience's size as it stands now.</p>
            </div>
          </div>

          <FilterBar
            query={query} onQuery={setQuery} placeholder="Search by name or id" dirty={dirty} onClear={clear}
            selects={[
              { id: "status", label: "Status", value: status, onChange: setStatus, items: [{ value: "all", label: "Every status" }].concat(BROADCAST_STATUS.map((s) => ({ value: s.id, label: s.label }))) },
              { id: "audience", label: "Audience", value: audience, onChange: setAudience, items: [{ value: "all", label: "Every audience" }].concat(data.audiences.map((a) => ({ value: a.id, label: a.name }))) },
            ]}
          />

          <BulkBar
            count={picked.length}
            note={pickedApprovable.length === picked.length
              ? "All of them are waiting on your approval."
              : pickedApprovable.length + " of the " + picked.length + " selected can be approved by you."}
            onClear={() => setSelected([])}
          >
            <Button variant="outline" size="sm" disabled={pickedApprovable.length === 0}
              onClick={() => { onBulkApprove(pickedApprovable); setSelected([]); }}>Approve and schedule</Button>
          </BulkBar>

          {filtered.length === 0 ? (
            <div style={{ padding: "var(--space-6) var(--gutter-page)" }}>
              <Empty>
                <EmptyHeader>
                  <EmptyMedia variant="icon"><Icon name="search-x" size={18} /></EmptyMedia>
                  <EmptyTitle>No broadcasts match those filters</EmptyTitle>
                  <EmptyDescription>Nothing among the {data.broadcasts.length} broadcasts in this workspace matches. Widen the filters and try again.</EmptyDescription>
                </EmptyHeader>
                <EmptyContent><Button onClick={clear}>Clear filters</Button></EmptyContent>
              </Empty>
            </div>
          ) : (
            <div className="md-tablewrap">
              <Table>
                <TableHeader>
                  <TableRow>
                    <TableHead style={{ width: "2.5rem" }}>
                      <Checkbox checked={allPicked} indeterminate={!allPicked && filtered.some((b) => selected.indexOf(b.id) > -1)}
                        aria-label="Select every broadcast shown" onCheckedChange={(checked) => setSelected(checked ? filtered.map((b) => b.id) : [])} />
                    </TableHead>
                    <TableHead><SortHead label="Broadcast" sortKey="name" sort={sort} onSort={onSort} /></TableHead>
                    <TableHead>Status</TableHead>
                    <TableHead className="md-drop-lg">Audience</TableHead>
                    <TableHead className="md-num"><SortHead label="Recipients" sortKey="recipients" sort={sort} onSort={onSort} /></TableHead>
                    <TableHead className="md-num md-drop-md"><SortHead label="Open rate" sortKey="open" sort={sort} onSort={onSort} /></TableHead>
                    <TableHead className="md-num md-drop-md">Click rate</TableHead>
                    <TableHead className="md-num"><SortHead label="Send time" sortKey="clock" sort={sort} onSort={onSort} /></TableHead>
                    <TableHead className="md-actions-head">Action</TableHead>
                  </TableRow>
                </TableHeader>
                <TableBody>
                  {rows.map((broadcast) => {
                    const transitions = broadcastTransitions(broadcast, viewer);
                    const recipients = broadcastRecipients(broadcast, data.audiences);
                    const clock = broadcastClock(broadcast);
                    const urgent = BROADCAST_FLAGS.isReviewUrgent(broadcast, now);
                    const recessed = transitions.length === 0;
                    return (
                      <TableRow key={broadcast.id} className={recessed ? "md-row--recessed" : undefined}>
                        <TableCell><Checkbox checked={selected.indexOf(broadcast.id) > -1} aria-label={"Select " + broadcast.name} onCheckedChange={() => toggle(broadcast.id)} /></TableCell>
                        <TableCell>
                          <span className="md-record">
                            <button type="button" className="md-link md-record__name" onClick={() => onNavigate("/broadcasts/" + broadcast.id)}>{broadcast.name}</button>
                            <span className="md-record__meta"><code>{broadcast.id}</code> · {memberName(data.members, broadcast.ownerId)}</span>
                          </span>
                        </TableCell>
                        <TableCell>
                          <span className="md-status"><StatusBadge values={BROADCAST_STATUS} value={broadcast.status} /></span>
                          {broadcast.failureReason ? <span className="md-sub">{broadcast.failureReason}</span> : null}
                        </TableCell>
                        <TableCell className="md-drop-lg">
                          <button type="button" className="md-link" onClick={() => onNavigate("/audiences/" + broadcast.audienceId)}>{audienceName(data.audiences, broadcast.audienceId)}</button>
                        </TableCell>
                        <TableCell className="md-num md-amount">
                          {formatCount(recipients.count)}
                          {recipients.projected ? <span className="md-sub">in the audience now</span> : <span className="md-sub">{formatPercent(broadcastDeliveryRate(broadcast))} handed off</span>}
                        </TableCell>
                        <TableCell className="md-num md-drop-md">{broadcastOpenRate(broadcast) === null ? <span className="md-muted">—</span> : formatPercent(broadcastOpenRate(broadcast))}</TableCell>
                        <TableCell className="md-num md-drop-md">{broadcastClickRate(broadcast) === null ? <span className="md-muted">—</span> : formatPercent(broadcastClickRate(broadcast))}</TableCell>
                        <TableCell className="md-num" title={clock ? formatAbsolute(clock) : ""}>
                          {clock ? formatWhen(clock, now) : <span className="md-muted">Never</span>}
                          {broadcast.status === "in_review" ? <span className={"md-sub" + (urgent ? " md-clock--warning" : "")}>{formatCountdown(broadcast.scheduledAt, now)}</span> : null}
                        </TableCell>
                        <TableCell className="md-actions">
                          <RowActions transitions={transitions} onRun={(t) => onBroadcastTransition(broadcast, t)} label={"Actions for " + broadcast.name} />
                        </TableCell>
                      </TableRow>
                    );
                  })}
                </TableBody>
              </Table>
            </div>
          )}

          <div className="md-tablefoot">
            <span className="md-footnote">Showing {filtered.length} of {data.broadcasts.length} broadcasts.</span>
            <span className="md-footnote">{formatCount(filtered.reduce((n, b) => n + broadcastRecipients(b, data.audiences).count, 0))} recipients across the rows shown.</span>
          </div>
        </section>
      </>
    );
  }

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