/* Meridian — the social layer: faces, notes and the mentions queue.

   A note is NOT a status field: it has no lifecycle, so enums.js carries no
   `comment.status`. Whether a mention is still owed is DERIVED — the person
   mentioned has not written on that record since (COMMENT_FLAGS.isAwaitingReply
   in enums.js), read by the queue card, the note itself and the count above the
   thread alike.

   Notes live only on records that HAVE a screen — a dispute and a card — so a
   mention in the queue always opens onto the thread it came from rather than a
   list where the conversation is invisible.

   A name is never written here: a mention token in a comment body is a member
   id (`@usr_tomas`), resolved through the one member fixture at render. */
(() => {
  const {
    Card, CardHeader, CardTitle, CardDescription, CardPanel, CardFooter, CardAction,
    Button, Textarea, Badge, Avatar,
  } = window.OriginDesignSystem_7c998b;

  const MENTION = /@usr_[a-z0-9_]+/g;
  const initialsOf = (name) => name.split(" ").map((w) => w[0]).slice(0, 2).join("");
  const personOf = (members, id) => members.find((m) => m.id === id) || { id: id, name: "somebody who has left", avatar: null, role: "" };
  /* What a record is CALLED comes from the record itself, never retyped. One
     branch per record type in RECORD_PATTERNS (nav.js), so a note can only be
     written on a record that has both a name and a route. */
  const RECORD_TITLES = {
    dispute: (data, id) => (data.disputes.find((r) => r.id === id) || {}).customer,
    card: (data, id) => (data.cards.find((r) => r.id === id) || {}).label,
    customer: (data, id) => (data.customers.find((r) => r.id === id) || {}).name,
    member: (data, id) => (data.members.find((r) => r.id === id) || {}).name,
  };
  const recordTitle = (data, record) => {
    const read = RECORD_TITLES[record.type];
    return (read && read(data, record.id)) || record.id;
  };

  function Face({ person, size = 24 }) {
    return (
      <FloatingTip label={person.name + (person.role ? " · " + person.role : "")} side="top">
        <span className="fd-face"><Avatar size={size} src={person.avatar} alt="" fallback={initialsOf(person.name)} /></span>
      </FloatingTip>
    );
  }

  /* Faces of the people on a record, not of the whole workspace: the ids come
     from peopleOn(), which reads the record's own person fields and its notes. */
  function FaceStack({ people, max = 4, size = 24 }) {
    if (!people.length) return null;
    const shown = people.slice(0, max);
    const rest = people.length - shown.length;
    return (
      <span className="fd-faces">
        {shown.map((p) => <Face key={p.id} person={p} size={size} />)}
        {rest > 0 ? <FloatingTip label={people.slice(max).map((p) => p.name).join(", ")} side="top"><span className="fd-faces__more">+{rest}</span></FloatingTip> : null}
      </span>
    );
  }

  function MentionText({ body, members }) {
    const parts = body.split(/(@usr_[a-z0-9_]+)/g);
    return (
      <span>
        {parts.map((part, i) => (part.indexOf("@usr_") === 0
          ? <span className="fd-mention" key={i}>@{personOf(members, part.slice(1)).name}</span>
          : <React.Fragment key={i}>{part}</React.Fragment>))}
      </span>
    );
  }

  function Note({ comment, comments, members, signedInId, now }) {
    const author = personOf(members, comment.authorId);
    const owed = comment.mentions.filter((id) => COMMENT_FLAGS.isAwaitingReply(comment, id, comments));
    return (
      <div className="fd-note">
        <Face person={author} size={28} />
        <div className="fd-note__body">
          <span className="fd-note__head">
            <span className="fd-note__who">{author.name}{comment.authorId === signedInId ? " (you)" : ""}</span>
            <span className="fd-note__when" title={formatAbsolute(comment.at)}>{formatWhen(comment.at, now)}</span>
            {owed.length ? <Badge size="sm" variant="warning">Waiting on {owed.map((id) => (id === signedInId ? "you" : personOf(members, id).name.split(" ")[0])).join(" and ")}</Badge> : null}
          </span>
          <p className="fd-note__text"><MentionText body={comment.body} members={members} /></p>
        </div>
      </div>
    );
  }

  /* Instant, and consequential: posting applies immediately and App.jsx raises
     an undo toast. Mentions are not a separate control — they are read out of
     the text, and the line under the box names who the draft will notify. */
  function Composer({ members, signedInId, onPost, placeholder }) {
    const [draft, setDraft] = React.useState("");
    const notifying = (draft.match(MENTION) || []).map((t) => t.slice(1)).filter((id) => members.some((m) => m.id === id));
    const others = members.filter((m) => m.id !== signedInId);
    const ready = draft.trim().length > 3;
    return (
      <div className="fd-composer">
        <Textarea rows={2} value={draft} placeholder={placeholder} aria-label={placeholder} onChange={(e) => setDraft(e.target.value)} />
        <div className="fd-composer__row">
          {others.map((m) => (
            <Button key={m.id} variant="outline" size="sm" onClick={() => setDraft((d) => (d ? d.replace(/\s*$/, " ") : "") + "@" + m.id + " ")}>
              <Face person={m} size={16} />{m.name.split(" ")[0]}
            </Button>
          ))}
          <span className="fd-composer__spacer" />
          <span className="fd-footnote">
            {notifying.length
              ? notifying.map((id) => personOf(members, id).name).join(" and ") + (notifying.length > 1 ? " get" : " gets") + " this in their queue"
              : "Nobody is notified unless you mention them"}
          </span>
          <Button size="sm" disabled={!ready} onClick={() => { onPost(draft.trim()); setDraft(""); }}>Post note</Button>
        </div>
      </div>
    );
  }

  /* The thread on a record. Oldest first, because a case is read forwards. */
  function ThreadCard({ record, data, signedInId, now, onPost, description }) {
    const thread = commentsOn(data.comments, record.type, record.id);
    const people = peopleOn(data.comments, record, data.members);
    const owed = thread.filter((c) => c.mentions.some((id) => COMMENT_FLAGS.isAwaitingReply(c, id, data.comments)));
    return (
      <Card>
        <CardHeader>
          <CardTitle>Notes</CardTitle>
          <CardDescription>{description}</CardDescription>
          <CardAction><FaceStack people={people} /></CardAction>
        </CardHeader>
        <CardPanel>
          <div className="fd-thread">
            {thread.length
              ? thread.map((c) => <Note key={c.id} comment={c} comments={data.comments} members={data.members} signedInId={signedInId} now={now} />)
              : <span className="fd-footnote">Nothing written on this one yet.</span>}
            <Composer members={data.members} signedInId={signedInId} placeholder="Write a note. Mention somebody to put it in their queue." onPost={(body) => onPost(record, body)} />
          </div>
        </CardPanel>
        <CardFooter className="fd-card-footer">
          <span className="fd-footnote">
            {thread.length
              ? thread.length + (thread.length === 1 ? " note · " : " notes · ")
              : ""}
            {people.length} {people.length === 1 ? "person" : "people"} on this record
            {owed.length ? " · " + owed.length + " waiting on a reply" : ""}
          </span>
        </CardFooter>
      </Card>
    );
  }

  /* The dashboard's social surface: every note that mentioned you and that you
     have not answered on that record since. One predicate, the same one the
     note badge and the thread footer read. */
  function ReplyQueueCard({ data, signedInId, now, onNavigate }) {
    const awaiting = mentionsAwaiting(data.comments, signedInId);
    return (
      <Card>
        <CardHeader>
          <CardTitle>Waiting on your reply</CardTitle>
          <CardDescription>
            {awaiting.length
              ? awaiting.length + " " + (awaiting.length === 1 ? "note mentions" : "notes mention") + " you and you have not written back on that record since."
              : "Nobody is waiting on a reply from you."}
          </CardDescription>
        </CardHeader>
        <CardPanel>
          {awaiting.length ? (
            <div className="fd-replies">
              {awaiting.map((c) => {
                const author = personOf(data.members, c.authorId);
                return (
                  <div className="fd-reply" key={c.id}>
                    <Face person={author} size={28} />
                    <div className="fd-note__body">
                      <span className="fd-note__head">
                        <span className="fd-note__who">{author.name}</span>
                        <span className="fd-note__when" title={formatAbsolute(c.at)}>{formatWhen(c.at, now)}</span>
                        <span className="fd-note__on">on {recordTitle(data, c.record)}</span>
                      </span>
                      <p className="fd-note__text"><MentionText body={c.body} members={data.members} /></p>
                    </div>
                    <Button variant="outline" size="sm" onClick={() => onNavigate(recordRoute(c.record))}>Open<Icon name="arrow-right" /></Button>
                  </div>
                );
              })}
            </div>
          ) : (
            <span className="fd-footnote">Notes you are mentioned in land here until you answer on the record.</span>
          )}
        </CardPanel>
      </Card>
    );
  }

  Object.assign(window, { Face, FaceStack, MentionText, ThreadCard, ReplyQueueCard, recordTitle });
})();
