/* Roster — the book. The desk's home screen.
   Commit model: INSTANT. Nothing on this screen commits: the text filter, the
   category dropdown and the availability tabs are harmless and apply as typed.
   There is no Save button and no undoable action here.
   Data state: populated. Empty and no-results are the other two branches of
   one conditional below — never on screen beside these bands.
   Scope: the whole book. There is no period filter, so no figure on this
   screen moves when the tabs, the category or the text filter change; the
   filters narrow the list only, and the footer states what is showing.
   Primary display: full-width creator bands rather than a table, because the
   thing a talent manager reads first is who somebody is, and a name at 30px
   beside a portrait says that faster than a cell ever will. */
(() => {
  const {
    Button, Input, Select, Badge, Tabs, TabsList, TabsTab, Separator,
    Empty, EmptyHeader, EmptyMedia, EmptyTitle, EmptyDescription, EmptyContent,
  } = window.OriginDesignSystem_7c998b;

  /* Tabs narrow the list only. Each runs its own predicate — never a slice. */
  const ROSTER_TABS = [
    { value: "free", label: "Free", predicate: (c) => CREATOR_FLAGS.isPitchable(c) },
    { value: "soon", label: "Coming free", predicate: (c, now) => CREATOR_FLAGS.isComingFree(c, now) },
    { value: "booked", label: "Booked", predicate: (c) => c.status === "booked" },
    { value: "all", label: "Everyone", predicate: () => true },
  ];

  const matches = (creator, query) => {
    const q = query.trim().toLowerCase();
    if (!q) return true;
    return [creator.name, creator.handle, creator.based]
      .concat(creator.categories.map((c) => labelOf(CATEGORIES, c)))
      .join(" ").toLowerCase().indexOf(q) > -1;
  };

  /* The availability band: the three answers to the question brands ask most
     often, over the ninety-day horizon every booking bar is drawn on. */
  function AvailabilityBand({ creators, deals, now, onNavigate }) {
    const free = pitchableCreators(creators);
    const soon = comingFreeCreators(creators, now);
    const booked = bookedCreators(creators);
    const paused = pausedCreators(creators);
    return (
      <div className="mq-bleed">
        <div className="mq-split">
          <div className="mq-section">
            <div className="mq-figures">
              <Figure size="xl" label="Free to pitch" value={free.length} note={free.map((c) => c.name.split(" ")[0]).join(", ") + " — no booking against them today"} />
              <Figure size="xl" label={"Coming free inside " + AGENCY_POLICY.comingFreeDays + " days"} value={soon.length} note={soon.length ? soon.map((c) => c.name.split(" ")[0] + " on " + formatAbsolute(c.bookedUntil).split(",")[0]).join(" · ") : "Nobody comes off a campaign this month"} />
              <Figure size="xl" label="Booked" value={booked.length} note={booked.length + " of " + creators.length + " on the book, and " + paused.length + " paused at their own request"} />
            </div>
            <p className="mq-note">Availability is counted against today. On a brief, it is counted against the brand's own window instead — a creator booked until October is free for a campaign that starts in November.</p>
          </div>
          <div className="mq-section">
            <div className="mq-section__head"><h2 className="mq-h2">Coming off a campaign</h2></div>
            {soon.length === 0 ? (
              <p className="mq-note">Nobody on the book comes free in the next {AGENCY_POLICY.comingFreeDays} days. The next to free up is {bookedCreators(creators).slice().sort((a, b) => a.bookedUntil - b.bookedUntil)[0].name} on {formatAbsolute(bookedCreators(creators).slice().sort((a, b) => a.bookedUntil - b.bookedUntil)[0].bookedUntil).split(",")[0]}.</p>
            ) : (
              <div className="mq-rows">
                {soon.slice().sort((a, b) => a.bookedUntil - b.bookedUntil).map((creator) => (
                  <div className="mq-row" key={creator.id}>
                    <Portrait creator={creator} size={36} />
                    <div className="mq-row__main">
                      <span className="mq-row__title">{creator.name}</span>
                      <span className="mq-row__meta">{unavailableBecause(creator, deals, now)}</span>
                    </div>
                    <div className="mq-row__side">
                      <span className="mq-mono mq-warn" title={formatAbsolute(creator.bookedUntil)}>{formatCountdown(creator.bookedUntil, now)}</span>
                    </div>
                  </div>
                ))}
              </div>
            )}
            <p className="mq-note">Ranked by the date their booking ends. Hold nobody against a brief without checking their exclusivities first.</p>
          </div>
        </div>
      </div>
    );
  }

  function RateCard({ creator }) {
    const card = rateCardOf(creator);
    return (
      <Floating
        align="start" width="17rem" role="dialog" panelClass="o-popover" label={creator.name + " rate card"}
        trigger={<Button variant="ghost" size="xs">Rate card<Icon name="chevron-down" /></Button>}
      >
        <div className="mq-col mq-col--tight" style={{ padding: "var(--space-2)" }}>
          <Eyebrow>{creator.name} · organic, before usage</Eyebrow>
          <div className="mq-lg">
            {card.map((rate) => (
              <LedgerRow key={rate.kind} label={rate.label} value={formatMoney(rate.cents)} />
            ))}
          </div>
          <p className="mq-note">Usage is charged on top: {USAGE_SCOPES.filter((u) => u.uplift > 0).map((u) => u.label.toLowerCase() + " +" + Math.round(u.uplift * 100) + "%").join(", ")}.</p>
        </div>
      </Floating>
    );
  }

  function CreatorBand({ creator, deals, now, onNavigate }) {
    const recessed = creator.status === "paused";
    const live = CREATOR_FLAGS.liveExclusivities(creator, now);
    const booking = creator.booking && creator.booking.dealId ? dealById(deals, creator.booking.dealId) : null;
    return (
      <article className={"mq-cband" + (recessed ? " mq-cband--recessed" : "")}>
        <Portrait creator={creator} size={104} />
        <div className="mq-cband__id">
          <h3 className="mq-cband__name"><button type="button" className="mq-link" onClick={() => onNavigate("/talent/" + creator.id)}>{creator.name}</button></h3>
          <span className="mq-mono mq-muted">@{creator.handle} · {creator.based} · signed {formatAbsolute(creator.signedAt).split(",")[0]}</span>
          <div className="mq-stack">
            {creator.categories.map((c) => <Badge key={c} variant="secondary" size="sm">{labelOf(CATEGORIES, c)}</Badge>)}
          </div>
          <p className="mq-cband__note">{creator.note}</p>
          <div className="mq-stack">
            <span className="mq-mono">{formatMoney(rateFloorOf(creator))} – {formatMoney(rateCeilOf(creator))} a piece</span>
            <RateCard creator={creator} />
          </div>
        </div>
        <div className="mq-cband__plat">
          <PlatformLadder creator={creator} />
        </div>
        <div className="mq-cband__avail">
          <Availability creator={creator} now={now} deals={deals} />
          {booking ? (
            <Button variant="ghost" size="xs" onClick={() => onNavigate("/deals/" + booking.id)}>{booking.brand} deal<Icon name="arrow-right" /></Button>
          ) : null}
          {live.length ? (
            <div className="mq-excl">
              <span className="mq-eyebrow mq-bad">Exclusivity</span>
              {live.map((e) => (
                <span className="mq-note" key={e.brand}>
                  <strong>{e.brand}</strong> in {labelOf(CATEGORIES, e.category).toLowerCase()} until {formatAbsolute(e.until).split(",")[0]}
                </span>
              ))}
            </div>
          ) : null}
        </div>
      </article>
    );
  }

  function RosterScreen({ data, now, onNavigate, pushToast }) {
    const [tab, setTab] = React.useState("all");
    const [category, setCategory] = React.useState("");
    const [query, setQuery] = React.useState("");
    const creators = data.creators;
    const spec = ROSTER_TABS.find((t) => t.value === tab);
    const inTab = creators.filter((c) => spec.predicate(c, now));
    /* Ordered by how much has actually been booked through the desk: the busiest
       names first, audience breaking the ties between creators on equal counts. */
    const campaigns = (c) => data.deals.filter((d) => d.creatorId === c.id).length;
    const rows = inTab
      .filter((c) => (category ? c.categories.indexOf(category) > -1 : true))
      .filter((c) => matches(c, query))
      .sort((a, b) => campaigns(b) - campaigns(a) || reachOf(b) - reachOf(a));
    const free = pitchableCreators(creators);
    const soon = comingFreeCreators(creators, now);

    const clearFilters = () => { setQuery(""); setCategory(""); setTab("all"); };

    return (
      <div className="mq-page">
        <PageHead
          eyebrow={MARQUE_AGENCY.name + " · " + MARQUE_AGENCY.book}
          title="The book"
          lede={free.length + " of " + creators.length + " creators are free to pitch today, and " + (soon.length ? soon.length + " more come off a campaign inside " + AGENCY_POLICY.comingFreeDays + " days" : "nobody else frees up this month") + ". Audience and engagement are read from the platform rows, so they move when the numbers do."}
          actions={
            <div className="mq-actions__row">
              <Button size="sm" onClick={() => onNavigate("/talent/new")}>New creator</Button>
              <ExportMenu scope="Roster" onExport={(format) => pushToast({ title: "Export started", description: "Roster · " + format + " — we'll email it to " + MARQUE_USER.name.split(" ")[0].toLowerCase() + "@marque.example" })} />
            </div>
          }
        />

        <AvailabilityBand creators={creators} deals={data.deals} now={now} onNavigate={onNavigate} />

        <section className="mq-section">
          <div className="mq-filters">
            <div className="mq-filters__text">
              <Input size="sm" value={query} onChange={(e) => setQuery(e.target.value)} aria-label="Filter the roster" placeholder="Filter by name, handle or city" startAddon={<Icon name="search" />} />
            </div>
            <div className="mq-stack">
              <Select
                size="sm" value={category} placeholder="Every category"
                items={[{ value: "", label: "Every category" }].concat(CATEGORIES.filter((c) => creators.some((cr) => cr.categories.indexOf(c.value) > -1)))}
                onValueChange={setCategory}
              />
              <Tabs value={tab} onValueChange={setTab}>
                <TabsList variant="underline" size="sm">
                  {ROSTER_TABS.map((t) => (
                    <TabsTab key={t.value} value={t.value} size="sm">
                      {t.label}<span className="mq-tab-count">{creators.filter((c) => t.predicate(c, now)).length}</span>
                    </TabsTab>
                  ))}
                </TabsList>
              </Tabs>
            </div>
          </div>

          {rows.length === 0 ? (
            <Empty>
              <EmptyHeader>
                <EmptyMedia variant="icon"><Icon name="search-x" size={18} /></EmptyMedia>
                <EmptyTitle>Nobody on the book matches that</EmptyTitle>
                <EmptyDescription>{inTab.length} creators sit under {spec.label.toLowerCase()}{category ? " in " + labelOf(CATEGORIES, category).toLowerCase() : ""}. Clear the filters to see the whole book.</EmptyDescription>
              </EmptyHeader>
              <EmptyContent>
                <Button onClick={clearFilters}>Clear filters</Button>
              </EmptyContent>
            </Empty>
          ) : (
            <div className="mq-roster">
              {rows.map((creator) => (
                <CreatorBand key={creator.id} creator={creator} deals={data.deals} now={now} onNavigate={onNavigate} />
              ))}
            </div>
          )}

          <div className="mq-foot">
            <span>Showing {rows.length} of {creators.length} creators{query ? " matching “" + query + "”" : ""}{category ? " in " + labelOf(CATEGORIES, category).toLowerCase() : ""} · sorted by campaigns booked, then total audience</span>
            <span>Rates are organic, before usage. A brief's quote adds the usage uplift.</span>
          </div>
        </section>
      </div>
    );
  }

  Object.assign(window, { RosterScreen, ROSTER_TABS });
})();
