/* Contacts — the sample the workspace can actually see, and one contact's page.

   Commit model: INSTANT. Nothing here stages; the filters narrow the list only
   and the figures above them are not moved by the text filter (§5.3) — the
   lifecycle scope IS applied to the figures, and sits above them.
   Data state: one branch each — populated, or no-results when the filters match
   nothing, which is the same branch of one conditional.

   Everything states its scope: this is the forty most recent contacts, not the
   6,142 in the workspace. Which audiences hold a contact is EVALUATED with the
   same segment rules the audience builder previews with — never stored. */
(() => {
  const {
    Table, TableHeader, TableBody, TableRow, TableHead, TableCell,
    Select, Button, Badge, Avatar,
  } = window.OriginDesignSystem_7c998b;

  const LIFECYCLE_TONE = { customer: "success", trial: "info", lead: "neutral", churned: "warning" };

  function ContactsScreen({ data, workspace, now, onNavigate }) {
    const [query, setQuery] = React.useState("");
    const [life, setLife] = React.useState("all");
    const [plan, setPlan] = React.useState("all");
    const { sort, onSort } = useSort("lastOpenAt", "desc");

    /* Scope first: the lifecycle control is above the figures and moves them. */
    const scoped = life === "all" ? data.contacts : data.contacts.filter((c) => c.lifecycle === life);
    /* Then the list filters, which move the rows only. */
    const filtered = scoped.filter((c) => {
      const q = query.trim().toLowerCase();
      if (q && c.name.toLowerCase().indexOf(q) < 0 && c.email.toLowerCase().indexOf(q) < 0) return false;
      if (plan !== "all" && c.plan !== plan) return false;
      return true;
    });
    const rows = sortRows(filtered, sort, {
      name: (c) => c.name, lifecycle: (c) => c.lifecycle, plan: (c) => c.plan,
      lastOpenAt: (c) => c.lastOpenAt, signupAt: (c) => c.signupAt,
    });

    const engaged = scoped.filter((c) => CONTACT_FLAGS.isEngaged(c, now));
    const quiet = scoped.filter((c) => CONTACT_FLAGS.isQuiet(c, now));
    const never = scoped.filter((c) => CONTACT_FLAGS.isNeverOpened(c));
    const buckets = contactBuckets(scoped, now).filter((b) => b.contacts.length);
    const dirty = !!query || plan !== "all";

    return (
      <>
        <PageHeader path="/contacts" title="Contacts" actions={
          <>
            <ExportMenu scope={filtered.length + " contacts in view"} onExport={() => {}} />
            <Button size="sm" onClick={() => onNavigate("/audiences/new")}><Icon name="plus" size={14} />New audience</Button>
          </>
        } />

        <div className="md-scope">
          <span className="md-scope__control">
            <span className="md-scope__label">Lifecycle</span>
            <span className="md-scope__select">
              <Select size="sm" aria-label="Lifecycle scope for the figures and the list" value={life} onValueChange={setLife}
                items={[{ value: "all", label: "Everyone in the sample" }].concat(LIFECYCLES.map((l) => ({ value: l.value, label: l.label })))} />
            </span>
          </span>
          <p className="md-scope__note">
            The figures and the table below cover {formatCount(scoped.length)} of the {formatCount(workspace.contacts)} contacts in {workspace.name} — the most recent additions, which is the sample this workspace exposes.
          </p>
        </div>

        <Tiles>
          <div className="md-tilestack md-tilestack--5">
            <Tile title="How the sample splits" note="Lifecycle, decomposed. The slices sum to the sample, not to the workspace.">
              <div className="md-donutrow">
                <Donut size={112} thickness={13} slices={buckets.map((b) => ({ key: b.value, value: b.contacts.length }))}
                  centreValue={formatCount(scoped.length)} centreLabel="in sample" />
                <DonutKey slices={buckets.map((b) => ({ key: b.value, label: b.label, display: String(b.contacts.length) }))} />
              </div>
            </Tile>

            <Tile title="Are they reading?" note="Opened something in the last 7 days, against the whole scoped sample.">
              <div className="md-donutrow">
                <Gauge size={124} percent={rate(engaged.length, scoped.length) * 100} value={formatPercent(rate(engaged.length, scoped.length))}
                  label="opened this week" tone={engaged.length / (scoped.length || 1) > 0.4 ? "success" : "warning"} />
                <KeyValues rows={[
                  { label: "Opened in the last 7 days", value: formatCount(engaged.length) },
                  { label: "Quiet for 30 days or more", value: formatCount(quiet.length) },
                  { label: "Never opened anything", value: formatCount(never.length) },
                  { label: "Unsubscribed, workspace-wide", value: formatCount(workspace.unsubscribed) },
                ]} />
              </div>
            </Tile>
          </div>

          <Tile span="7" title="Where they sit"
            note="Audiences this sample actually reaches, most of it first. Ordered by how many of the sample each holds, which is the number on the row.">
            {(() => {
              const rows = data.audiences
                .map((audience) => ({ audience, held: scoped.filter((c) => contactAudiences(data, c, now).some((a) => a.id === audience.id)) }))
                .filter((row) => row.held.length)
                .sort((a, b) => b.held.length - a.held.length);
              const unreached = data.audiences.length - rows.length;
              return (
                <>
                  {rows.length === 0 ? (
                    <p className="md-empty">No audience holds anybody in this sample.</p>
                  ) : (
                    <div className="md-queue">
                      {rows.map(({ audience, held }) => (
                        <div className="md-queue__row" key={audience.id}>
                          <div className="md-queue__main">
                            <button type="button" className="md-link" onClick={() => onNavigate("/audiences/" + audience.id)}>{audience.name}</button>
                            <span className="md-footnote">{formatCount(audience.size)} people in the audience as a whole</span>
                          </div>
                          <div className="md-queue__side"><Chip icon="user">{held.length} in sample</Chip></div>
                        </div>
                      ))}
                    </div>
                  )}
                  {unreached ? (
                    <div className="md-tile__foot">
                      <span>
                        {unreached === 1 ? "One audience holds" : unreached + " audiences hold"} nobody from this sample
                        {" — "}
                        {data.audiences.filter((a) => !rows.some((r) => r.audience.id === a.id)).map((a) => a.name).join(", ")}
                        {". A hand-kept list is only matched by name, so the sample rarely lands in one."}
                      </span>
                    </div>
                  ) : null}
                </>
              );
            })()}
          </Tile>

          <Tile span="12" flush title={"The sample — " + rows.length + (rows.length === 1 ? " contact" : " contacts")}
            note="Filters narrow this table only; the figures above are scoped by lifecycle, not by these.">
            <div style={{ padding: "0 var(--gutter-card)" }}>
              <FilterBar query={query} onQuery={setQuery} placeholder="Search name or email…" dirty={dirty}
                onClear={() => { setQuery(""); setPlan("all"); }}
                selects={[{ id: "plan", label: "Plan", value: plan, onChange: setPlan, items: [{ value: "all", label: "Any plan" }].concat(PLANS.map((p) => ({ value: p.value, label: p.label }))) }]} />
            </div>
            {rows.length === 0 ? (
              <div style={{ padding: "var(--gutter-card)" }}>
                <p className="md-empty">No contact in the sample matches those filters.</p>
                <Button variant="outline" size="sm" onClick={() => { setQuery(""); setPlan("all"); }}>Clear filters</Button>
              </div>
            ) : (
              <div className="md-tablewrap">
                <Table>
                  <TableHeader>
                    <TableRow>
                      <TableHead><SortHead label="Contact" sortKey="name" sort={sort} onSort={onSort} /></TableHead>
                      <TableHead><SortHead label="Lifecycle" sortKey="lifecycle" sort={sort} onSort={onSort} /></TableHead>
                      <TableHead><SortHead label="Plan" sortKey="plan" sort={sort} onSort={onSort} /></TableHead>
                      <TableHead><SortHead label="Last opened" sortKey="lastOpenAt" sort={sort} onSort={onSort} /></TableHead>
                      <TableHead><SortHead label="Joined" sortKey="signupAt" sort={sort} onSort={onSort} /></TableHead>
                    </TableRow>
                  </TableHeader>
                  <TableBody>
                    {rows.map((contact) => (
                      <TableRow key={contact.id}>
                        <TableCell>
                          <span className="md-person">
                            <Avatar size={28} src={null} alt="" fallback={initialsOf(contact.name)} />
                            <span className="md-person__text">
                              <button type="button" className="md-link md-person__name" onClick={() => onNavigate("/contacts/" + contact.id)}>{contact.name}</button>
                              <span className="md-person__role">{contact.email}</span>
                            </span>
                          </span>
                        </TableCell>
                        <TableCell><Badge size="sm" variant={LIFECYCLE_TONE[contact.lifecycle] === "neutral" ? "secondary" : LIFECYCLE_TONE[contact.lifecycle]}>{labelOf(LIFECYCLES, contact.lifecycle)}</Badge></TableCell>
                        <TableCell>{labelOf(PLANS, contact.plan)}</TableCell>
                        <TableCell>
                          <span className={contact.lastOpenAt == null || CONTACT_FLAGS.isQuiet(contact, now) ? "md-muted" : ""} title={contact.lastOpenAt ? formatAbsolute(contact.lastOpenAt) : "Never"}>
                            {contact.lastOpenAt == null ? "Never" : formatWhen(contact.lastOpenAt, now)}
                          </span>
                        </TableCell>
                        <TableCell><span title={formatAbsolute(contact.signupAt)}>{formatWhen(contact.signupAt, now)}</span></TableCell>
                      </TableRow>
                    ))}
                  </TableBody>
                </Table>
              </div>
            )}
          </Tile>
        </Tiles>
      </>
    );
  }

  function ContactScreen({ data, workspace, now, contactId, onNavigate }) {
    const contact = contactById(data.contacts, contactId);
    if (!contact) return <RouteNotBuilt path={"/contacts/" + contactId} onNavigate={onNavigate} />;
    const audiences = contactAudiences(data, contact, now);
    const sends = contactSends(data, contact, now);
    const engaged = CONTACT_FLAGS.isEngaged(contact, now);
    const tenureDays = Math.round((now - contact.signupAt) / 864e5);

    return (
      <>
        <PageHeader path="/contacts/:id" params={{ id: contactId }} title={contact.name} crumb={contact.name} actions={
          <Button variant="outline" size="sm" onClick={() => onNavigate("/contacts")}><Icon name="arrow-left" size={14} />All contacts</Button>
        } />

        <Tiles>
          <Tile span="7" tone="hero">
            <div className="md-hero">
              <Avatar className="md-hero__avatar" size={80} src={null} alt="" fallback={initialsOf(contact.name)} />
              <div className="md-hero__text">
                <span className="md-hero__name">{contact.name}</span>
                <span className="md-hero__line">{contact.email}</span>
                <div className="md-chips">
                  <Badge size="sm" variant={LIFECYCLE_TONE[contact.lifecycle] === "neutral" ? "secondary" : LIFECYCLE_TONE[contact.lifecycle]}>{labelOf(LIFECYCLES, contact.lifecycle)}</Badge>
                  <Chip icon="credit-card">{labelOf(PLANS, contact.plan)}</Chip>
                  <Chip icon="calendar">{tenureDays} days with {workspace.name}</Chip>
                  <Chip tone={engaged ? undefined : "warning"} icon="mail-open">
                    {contact.lastOpenAt == null ? "Never opened anything" : "Last opened " + formatWhen(contact.lastOpenAt, now)}
                  </Chip>
                </div>
              </div>
            </div>
          </Tile>

          <Tile span="5" title="What reaches them" note="Evaluated now against this contact, with the same rule predicates the audience builder previews with — never a stored membership.">
            <StatRow>
              <StatTile label="Audiences" value={formatCount(audiences.length)}
                qualifier={audiences.length ? "Segments and lists this contact currently matches" : "This contact matches no audience — nothing sends to them"} />
              <StatTile label="Live journeys" value={formatCount(sends.journeys.length)}
                qualifier={sends.journeys.length ? "Running continuously against an audience holding them" : "No live journey points at an audience holding them"} />
            </StatRow>
          </Tile>

          <Tile span="5" title="The audiences holding them">
            {audiences.length === 0 ? <p className="md-empty">No audience matches this contact today.</p> : (
              <div className="md-queue">
                {audiences.map((audience) => (
                  <div className="md-queue__row" key={audience.id}>
                    <div className="md-queue__main">
                      <button type="button" className="md-link" onClick={() => onNavigate("/audiences/" + audience.id)}>{audience.name}</button>
                      <span className="md-footnote">{audience.rule}{audience.sampleRuleNote ? " · " + audience.sampleRuleNote : ""}</span>
                    </div>
                    <div className="md-queue__side"><Chip>{formatCount(audience.size)} people</Chip></div>
                  </div>
                ))}
              </div>
            )}
          </Tile>

          <Tile span="7" title="What has gone to them" note="Broadcasts that went to an audience holding this contact, newest first, plus the journeys still running.">
            {sends.broadcasts.length === 0 && sends.journeys.length === 0 ? (
              <p className="md-empty">Nothing has been sent to an audience holding this contact.</p>
            ) : (
              <div className="md-queue">
                {sends.broadcasts.map((broadcast) => (
                  <div className="md-queue__row" key={broadcast.id}>
                    <div className="md-queue__main">
                      <button type="button" className="md-link" onClick={() => onNavigate("/broadcasts/" + broadcast.id)}>{broadcast.name}</button>
                      <span className="md-footnote">{audienceName(data.audiences, broadcast.audienceId)} · {formatPercent(broadcastOpenRate(broadcast))} opened it overall</span>
                    </div>
                    <div className="md-queue__side">
                      <StatusBadge values={BROADCAST_STATUS} value={broadcast.status} />
                      <span className="md-footnote" title={formatAbsolute(broadcast.sentAt)}>{formatWhen(broadcast.sentAt, now)}</span>
                    </div>
                  </div>
                ))}
                {sends.journeys.map((journey) => (
                  <div className="md-queue__row" key={journey.id}>
                    <div className="md-queue__main">
                      <button type="button" className="md-link" onClick={() => onNavigate("/journeys/" + journey.id)}>{journey.name}</button>
                      <span className="md-footnote">Runs continuously · {journey.trigger}</span>
                    </div>
                    <div className="md-queue__side"><StatusBadge values={JOURNEY_STATUS} value={journey.status} /></div>
                  </div>
                ))}
              </div>
            )}
            <div className="md-tile__foot">
              <span>Per-contact open and click history is not held in this workspace — only the last open date is.</span>
            </div>
          </Tile>
        </Tiles>
      </>
    );
  }

  Object.assign(window, { ContactsScreen, ContactScreen });
})();
