/* Activity — the desk's timeline, read as a feed rather than a table.

   Commit model: INSTANT, and this screen commits nothing but a note: everything
   listed is a reading of the records. Every row is a field on a payment,
   payout, dispute, expense or card, plus the notes — activityFeed() in
   metrics.js does the deriving, so the feed cannot drift from the desk and
   there is no activity fixture to keep in step.

   Layout: a centred reading column with a side rail beside it — the rail is
   filters of the same arrays the feed reads (who has been working, where the
   talking is, what is on a clock), so it cannot say anything the timeline does
   not. The feed itself is read down rather than scanned across, so its width is
   capped at a comfortable measure and the rail carries the actor's face at the
   moment they did something. A note is a POST: it gets a card, its own words at
   reading size, and a reply that lands on the record it was written on.
   Everything the platform did is a QUIET LINE on the same rail: an icon, one
   sentence, the record. The difference in weight is the whole point — a
   sentence somebody wrote outranks a state change. A post still owed a reply
   from you is tinted rather than outlined: it is a nudge, not a warning.

   Data state: populated. The scope control is harmless and applies bare; it
   narrows the feed only, so the figures above it do not move. */
(() => {
  const {
    Card, CardHeader, CardTitle, CardDescription, CardPanel, CardFooter,
    Button, Badge, Tabs, TabsList, TabsTab, Avatar, Separator,
    Empty, EmptyHeader, EmptyMedia, EmptyTitle, EmptyDescription, EmptyContent,
  } = window.OriginDesignSystem_7c998b;

  const KIND_ICON = { note: "message-square", money: "arrow-left-right", spend: "receipt" };
  const initialsOf = (name) => name.split(" ").map((w) => w[0]).slice(0, 2).join("");

  /* A note somebody wrote: the post. */
  function NotePost({ event, data, now, signedInId, onNavigate }) {
    const comment = event.comment;
    const author = data.members.find((m) => m.id === comment.authorId) || { id: null, name: "somebody who has left", avatar: null, role: "" };
    const owed = comment.mentions.filter((id) => COMMENT_FLAGS.isAwaitingReply(comment, id, data.comments));
    const yours = owed.indexOf(signedInId) > -1;
    const mine = comment.authorId === signedInId;
    const people = peopleOn(data.comments, comment.record, data.members);
    return (
      <article className={"fd-post" + (yours ? " fd-post--owed" : "")}>
        <span className="fd-post__face"><Face person={author} size={40} /></span>
        <div className="fd-post__body">
          <header className="fd-post__head">
            <span className="fd-post__who">{author.name}{mine ? " (you)" : ""}</span>
            <span className="fd-post__dot" aria-hidden="true">·</span>
            <span className="fd-post__when" title={formatAbsolute(comment.at)}>{formatWhen(comment.at, now)}</span>
            <button type="button" className="fd-post__on" onClick={() => onNavigate(event.route)}>
              <Icon name={comment.record.type === "dispute" ? "shield-alert" : comment.record.type === "card" ? "credit-card" : comment.record.type === "customer" ? "building-2" : "users"} size={12} />
              {recordTitle(data, comment.record)}
            </button>
          </header>
          <p className="fd-post__text"><MentionText body={comment.body} members={data.members} /></p>
          <footer className="fd-post__foot">
            {owed.length ? (
              <Badge size="sm" variant="warning">
                {yours && owed.length === 1 ? "Waiting on you" : "Waiting on " + owed.map((id) => (id === signedInId ? "you" : (data.members.find((m) => m.id === id) || {}).name.split(" ")[0])).join(" and ")}
              </Badge>
            ) : null}
            <span className="fd-post__people"><FaceStack people={people} size={20} max={3} /></span>
            <span className="fd-post__spacer" />
            <Button variant="ghost" size="sm" onClick={() => onNavigate(event.route)}>
              <Icon name="message-square" size={14} />{yours ? "Reply" : "Open thread"}
            </Button>
          </footer>
        </div>
      </article>
    );
  }

  /* Something the desk did: the quiet line. */
  function EventLine({ event, data, now, onNavigate }) {
    const actor = event.actorId ? data.members.find((m) => m.id === event.actorId) : null;
    return (
      <div className="fd-line">
        {actor
          ? <span className="fd-line__face"><Face person={actor} size={24} /></span>
          : <span className="fd-line__mark" aria-hidden="true"><Icon name={KIND_ICON[event.kind]} size={13} /></span>}
        <p className="fd-line__text">
          <span className="fd-line__who">{actor ? actor.name : "Meridian"}</span>
          {" "}{event.title}
          <span className="fd-line__dot" aria-hidden="true"> · </span>
          <button type="button" className="fd-link" onClick={() => onNavigate(event.route)}>{event.body}</button>
        </p>
        <span className="fd-line__when" title={formatAbsolute(event.at)}>{formatWhen(event.at, now)}</span>
      </div>
    );
  }

  /* The side rail: who is here, what is on a clock, and where the desk's own
     words are. Each card is a filter of the same arrays the feed reads — the
     rail cannot say anything the timeline does not. */
  function FeedAside({ data, now, events, onNavigate }) {
    /* Ranked by what they have actually done in this window, not by name. */
    const ranked = data.members
      .map((m) => ({ member: m, acts: events.filter((e) => e.actorId === m.id).length, notes: data.comments.filter((c) => c.authorId === m.id).length }))
      .filter((row) => row.acts > 0)
      .sort((a, b) => b.acts - a.acts);
    const clocks = disputesNeedingEvidence(data.disputes);
    const busiest = data.comments.reduce((map, c) => {
      const key = c.record.type + ":" + c.record.id;
      map[key] = map[key] || { record: c.record, count: 0, at: 0, people: [] };
      map[key].count += 1;
      map[key].at = Math.max(map[key].at, c.at);
      if (map[key].people.indexOf(c.authorId) === -1) map[key].people.push(c.authorId);
      return map;
    }, {});
    const threads = Object.keys(busiest).map((k) => busiest[k]).sort((a, b) => b.count - a.count || b.at - a.at).slice(0, 4);

    return (
      <aside className="fd-aside">
        <Card className="fd-card">
          <CardHeader>
            <CardTitle>Who has been working</CardTitle>
            <CardDescription>Counted from the records, this window.</CardDescription>
          </CardHeader>
          <CardPanel>
            <div className="fd-rank">
              {ranked.map((row) => (
                <button type="button" className="fd-rank__row" key={row.member.id} onClick={() => onNavigate(recordRoute({ type: "member", id: row.member.id }))}>
                  <Face person={row.member} size={28} />
                  <span className="fd-record">
                    <span className="fd-record__name">{row.member.name}{row.member.id === MERIDIAN_SIGNED_IN ? " (you)" : ""}</span>
                    <span className="fd-record__meta">{row.notes ? row.notes + (row.notes === 1 ? " note" : " notes") : "No notes"} · {row.member.role}</span>
                  </span>
                  <span className="fd-rank__count">{row.acts}</span>
                </button>
              ))}
            </div>
          </CardPanel>
          <CardFooter className="fd-card-footer">
            <span className="fd-footnote">{data.members.length - ranked.length ? (data.members.length - ranked.length) + " of " + data.members.length + " have done nothing in this window." : "Everybody here has done something."}</span>
          </CardFooter>
        </Card>

        {threads.length ? (
          <Card className="fd-card">
            <CardHeader>
              <CardTitle>Where the talking is</CardTitle>
              <CardDescription>Records with more than one note on them.</CardDescription>
            </CardHeader>
            <CardPanel>
              <div className="fd-picklist">
                {threads.map((thread) => (
                  <button type="button" className="fd-pick" key={thread.record.type + thread.record.id} onClick={() => onNavigate(recordRoute(thread.record))}>
                    <span className="fd-list__main">
                      <span className="fd-record__name">{recordTitle(data, thread.record)}</span>
                      <span className="fd-record__meta">{thread.count} {thread.count === 1 ? "note" : "notes"} · last {formatWhen(thread.at, now)}</span>
                    </span>
                    <span className="fd-list__side"><FaceStack people={peopleOn(data.comments, thread.record, data.members)} size={20} max={3} /></span>
                  </button>
                ))}
              </div>
            </CardPanel>
          </Card>
        ) : null}

        {clocks.length ? (
          <Card className="fd-card">
            <CardHeader>
              <CardTitle>On a clock</CardTitle>
              <CardDescription>Evidence the network is still waiting for.</CardDescription>
            </CardHeader>
            <CardPanel>
              <div className="fd-picklist">
                {clocks.map((dispute) => (
                  <button type="button" className="fd-pick" key={dispute.id} onClick={() => onNavigate(recordRoute({ type: "dispute", id: dispute.id }))}>
                    <span className="fd-list__main">
                      <span className="fd-record__name">{dispute.customer}</span>
                      <span className="fd-record__meta">{dispute.reason}</span>
                    </span>
                    <span className="fd-list__side">
                      <span className="fd-amount">{formatMoney(dispute.amount)}</span>
                      <span className="fd-clock">{formatCountdown(dispute.evidenceDueAt, now)}</span>
                    </span>
                  </button>
                ))}
              </div>
            </CardPanel>
          </Card>
        ) : null}
      </aside>
    );
  }

  function ActivityScreen({ data, now, onNavigate }) {
    const [scope, setScope] = React.useState("all");
    const events = activityFeed(data, now);
    const shown = activityInScope(events, scope);
    const awaiting = mentionsAwaiting(data.comments, MERIDIAN_SIGNED_IN);
    const actors = data.members.filter((m) => events.some((e) => e.actorId === m.id));
    const scopeLabel = labelOf(ACTIVITY_SCOPES, scope);
    const notes = events.filter((e) => e.kind === "note");

    /* One divider a day, so the reader can see the shape of a week. */
    const days = [];
    shown.forEach((event) => {
      const key = formatDayFull(event.at);
      const last = days[days.length - 1];
      if (last && last.key === key) last.rows.push(event);
      else days.push({ key: key, at: event.at, rows: [event] });
    });
    const today = formatDayFull(now);

    return (
      <div className="fd-page">
        <PageHeader path="/activity" title="Activity" />

        <div className="fd-metrics">
          <MetricTile icon="message-square" label="Things that happened" value={formatCount(events.length)} qualifier={notes.length + " notes, " + events.filter((e) => e.kind === "money").length + " money movements, " + events.filter((e) => e.kind === "spend").length + " card decisions"} />
          <MetricTile icon="reply" label="Waiting on your reply" value={formatCount(awaiting.length)} qualifier={awaiting.length ? "Notes that mentioned you and have had no answer from you since" : "Nobody is waiting on you"} />
          <MetricTile icon="users" label="People on the desk" value={formatCount(actors.length)} qualifier={"of " + data.members.length + " have done something in this window"} />
        </div>

        <div className="fd-feedlayout">
          <div className="fd-feedwrap">
            <div className="fd-feedhead">
              <Tabs value={scope} onValueChange={setScope}>
                <TabsList size="sm">
                  {ACTIVITY_SCOPES.map((s) => <TabsTab key={s.value} value={s.value} size="sm">{s.label}</TabsTab>)}
                </TabsList>
              </Tabs>
              <span className="fd-footnote">Showing {shown.length} of {events.length}</span>
            </div>

            {/* Writing here is writing on a record: a note needs somewhere to
                live, so this sends you to the thread rather than posting into a
                feed nothing owns. */}
            {awaiting.length ? (
              <div className="fd-feedcall">
                <span className="fd-feedcall__faces"><FaceStack people={awaiting.map((c) => data.members.find((m) => m.id === c.authorId)).filter(Boolean)} size={24} max={3} /></span>
                <p className="fd-feedcall__text">
                  <strong>{awaiting.length} {awaiting.length === 1 ? "person is" : "people are"} waiting on you.</strong>{" "}
                  {awaiting.length === 1 ? "One note mentioned you and has had no answer since." : "Their notes mentioned you and have had no answer since."}
                </p>
                <Button size="sm" onClick={() => onNavigate(recordRoute(awaiting[0].record))}>
                  Reply to {(data.members.find((m) => m.id === awaiting[0].authorId) || {}).name.split(" ")[0]}<Icon name="arrow-right" />
                </Button>
              </div>
            ) : null}

            {shown.length ? (
              <div className="fd-timeline">
                {days.map((day) => (
                  <section className="fd-timeline__day" key={day.key}>
                    <h2 className="fd-timeline__label"><span>{day.key === today ? "Today" : day.key}</span></h2>
                    <div className="fd-timeline__rows">
                      {day.rows.map((event) => (event.comment
                        ? <NotePost key={event.id} event={event} data={data} now={now} signedInId={MERIDIAN_SIGNED_IN} onNavigate={onNavigate} />
                        : <EventLine key={event.id} event={event} data={data} now={now} onNavigate={onNavigate} />))}
                    </div>
                  </section>
                ))}
                <p className="fd-timeline__end">That is everything on the desk. Nothing here is stored — every line is read off the record it names.</p>
              </div>
            ) : (
              <Card>
                <CardPanel>
                  <Empty>
                    <EmptyHeader>
                      <EmptyMedia variant="icon"><Icon name={KIND_ICON[scope] || "message-square"} size={18} /></EmptyMedia>
                      <EmptyTitle>Nothing of that kind yet</EmptyTitle>
                      <EmptyDescription>{events.length} things have happened on the desk; none of them are {scopeLabel.toLowerCase()}.</EmptyDescription>
                    </EmptyHeader>
                    <EmptyContent>
                      <Button onClick={() => setScope("all")}>Show everything</Button>
                    </EmptyContent>
                  </Empty>
                </CardPanel>
              </Card>
            )}
          </div>

          <FeedAside data={data} now={now} events={events} onNavigate={onNavigate} />
        </div>
      </div>
    );
  }

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