/* Calendar — what goes out when. Month and week are two VIEWS of one
   destination, so they are tabs on the page, not two routes (§5, navigation
   ownership).

   Commit model: INSTANT. Nothing stages; a cell opens the record.
   Data state: one branch — populated. A month with nothing dated in it still
   draws its grid, and each empty day says nothing rather than pretending.

   What is dated is a broadcast's send time. Live journeys are NOT drawn on a day:
   they send continuously, so they sit in their own tile beside the grid instead
   of claiming a date they do not have. */
(() => {
  const { Button, Badge, Tabs, TabsList, TabsTab, TabsPanel } = window.OriginDesignSystem_7c998b;

  const DOW = ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
  const monthStartOf = (ms) => { const d = new Date(ms); return new Date(d.getFullYear(), d.getMonth(), 1).getTime(); };
  const weekStartOf = (ms) => { const d = new Date(startOfDay(ms)); return d.getTime() - ((d.getDay() + 6) % 7) * 864e5; };
  const timeOf = (at) => new Date(at).toLocaleTimeString("en-GB", { hour: "2-digit", minute: "2-digit" });

  /* A day cell is narrow by construction, so the chip is recoverable rather than
     complete: the name takes two lines and the tooltip carries what a cell
     cannot hold — the audience, the size and the clock. */
  function Entry({ entry, data, now, onNavigate, wide }) {
    const broadcast = data.broadcasts.find((b) => b.id === entry.id);
    const recipients = broadcast ? broadcastRecipients(broadcast, data.audiences) : null;
    const chip = (
      <button type="button" className={"md-cal__entry" + (wide ? " md-cal__entry--wide" : "")} onClick={() => onNavigate(entry.route)}>
        <span className="md-cal__entry-name">{entry.name}</span>
        <span className="md-cal__entry-when">{timeOf(entry.at)}{wide ? " · " + statusValue(BROADCAST_STATUS, entry.status).label : ""}</span>
      </button>
    );
    if (wide) return chip;
    return (
      <FloatingTip side="top" label={
        <span style={{ display: "block", maxWidth: "18rem" }}>
          {entry.name} — {statusValue(BROADCAST_STATUS, entry.status).label.toLowerCase()}
          {recipients ? ", " + formatCount(recipients.count) + " in " + audienceName(data.audiences, broadcast.audienceId) : ""}
          {" · " + timeOf(entry.at) + ", " + (entry.at >= now ? formatCountdown(entry.at, now) : formatWhen(entry.at, now))}
        </span>
      }>{chip}</FloatingTip>
    );
  }

  function CalendarScreen({ data, now, viewer, onNavigate, onNewBroadcast }) {
    const [view, setView] = React.useState("month");
    const [monthAt, setMonthAt] = React.useState(monthStartOf(now));
    const [weekAt, setWeekAt] = React.useState(weekStartOf(now));

    const cells = calendarMonth(data, monthAt, now);
    const week = calendarWeek(data, weekAt, now);
    const entries = calendarEntries(data);
    const inMonth = entries.filter((e) => monthStartOf(e.at) === monthAt);
    const inWeek = entries.filter((e) => weekStartOf(e.at) === weekAt);
    const live = liveJourneys(data.journeys);
    const upcoming = entries.filter((e) => e.at >= now).sort((a, b) => a.at - b.at);
    const scope = view === "month" ? inMonth : inWeek;
    const reach = scope.reduce((n, e) => n + broadcastRecipients(data.broadcasts.find((b) => b.id === e.id), data.audiences).count, 0);

    return (
      <>
        <PageHeader path="/calendar" title="Calendar" actions={
          <Button size="sm" onClick={onNewBroadcast}><Icon name="plus" size={14} />New broadcast</Button>
        } />

        <Tiles>
          <Tile span="12" flush
            title={view === "month"
              ? new Date(monthAt).toLocaleDateString("en-GB", { month: "long", year: "numeric" })
              : "Week of " + new Date(weekAt).toLocaleDateString("en-GB", { day: "numeric", month: "long" })}
            note={scope.length ? scope.length + (scope.length === 1 ? " dated send" : " dated sends") + " in view, reaching " + formatCount(reach) + " people as the audiences stand now." : "Nothing dated in this view."}
            actions={
              <>
                <Tabs value={view} onValueChange={setView}>
                  <TabsList size="sm">
                    <TabsTab value="month" size="sm">Month</TabsTab>
                    <TabsTab value="week" size="sm">Week</TabsTab>
                  </TabsList>
                </Tabs>
                <Button variant="outline" size="icon-sm" aria-label="Previous"
                  onClick={() => view === "month" ? setMonthAt(monthStartOf(monthAt - 1)) : setWeekAt(weekAt - 7 * 864e5)}>
                  <Icon name="chevron-left" size={14} />
                </Button>
                <Button variant="outline" size="sm"
                  onClick={() => { setMonthAt(monthStartOf(now)); setWeekAt(weekStartOf(now)); }}>Today</Button>
                <Button variant="outline" size="icon-sm" aria-label="Next"
                  onClick={() => view === "month" ? setMonthAt(monthStartOf(new Date(monthAt).setMonth(new Date(monthAt).getMonth() + 1))) : setWeekAt(weekAt + 7 * 864e5)}>
                  <Icon name="chevron-right" size={14} />
                </Button>
              </>
            }>
            <div style={{ padding: "0 var(--gutter-card) var(--gutter-card)" }}>
              {view === "month" ? (
                <div className="md-cal">
                  {DOW.map((d) => <span className="md-cal__dow" key={d}>{d}</span>)}
                  {cells.map((cell, i) => cell === null
                    ? <span className="md-cal__cell md-cal__cell--empty" key={"e" + i} />
                    : (
                      <div className={"md-cal__cell" + (cell.today ? " md-cal__cell--today" : "")} key={cell.at}>
                        <span className="md-cal__day">
                          <span>{cell.day}</span>
                          {cell.entries.length ? <Badge size="sm" variant="secondary">{cell.entries.length}</Badge> : null}
                        </span>
                        {cell.entries.map((entry) => <Entry key={entry.id} entry={entry} data={data} now={now} onNavigate={onNavigate} />)}
                      </div>
                    ))}
                </div>
              ) : (
                <div className="md-cal__week">
                  {week.map((day) => (
                    <div className="md-cal__wrow" key={day.at}>
                      <span className="md-cal__wday">
                        {new Date(day.at).toLocaleDateString("en-GB", { weekday: "long" })}
                        <span>{new Date(day.at).toLocaleDateString("en-GB", { day: "numeric", month: "short" })}{day.today ? " · today" : ""}</span>
                      </span>
                      <div style={{ display: "flex", flexWrap: "wrap", gap: "var(--space-2)" }}>
                        {day.entries.length === 0
                          ? <span className="md-footnote">Nothing dated.</span>
                          : day.entries.map((entry) => (
                            <span key={entry.id} style={{ minWidth: "14rem" }}><Entry entry={entry} data={data} now={now} onNavigate={onNavigate} wide /></span>
                          ))}
                      </div>
                    </div>
                  ))}
                </div>
              )}
            </div>
          </Tile>

          <Tile span="5" tone="hero" title="Next out of the door" note="Dated sends from now on, soonest first — the same records the grid draws.">
            {upcoming.length === 0 ? <p className="md-empty">Nothing is scheduled.</p> : (
              <div className="md-queue">
                {upcoming.slice(0, 4).map((entry) => {
                  const broadcast = data.broadcasts.find((b) => b.id === entry.id);
                  return (
                    <div className="md-queue__row" key={entry.id}>
                      <div className="md-queue__main">
                        <button type="button" className="md-link" onClick={() => onNavigate(entry.route)}>{entry.name}</button>
                        <span className="md-footnote">
                          {formatCount(broadcastRecipients(broadcast, data.audiences).count)} in {audienceName(data.audiences, broadcast.audienceId)}
                        </span>
                      </div>
                      <div className="md-queue__side">
                        <StatusBadge values={BROADCAST_STATUS} value={broadcast.status} />
                        <span className="md-clock md-muted" title={formatAbsolute(entry.at)}>{formatCountdown(entry.at, now)}</span>
                      </div>
                    </div>
                  );
                })}
              </div>
            )}
          </Tile>

          <Tile span="4" title="Running continuously" note="Live journeys have no date: they send whenever somebody meets the trigger, which is why they are not on the grid.">
            <div className="md-queue">
              {live.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">{journey.trigger} · last sent {formatWhen(journey.lastSendAt, now)}</span>
                  </div>
                  <div className="md-queue__side"><Chip icon="users">{formatCount(journeyEnrolled(journey))} in it</Chip></div>
                </div>
              ))}
            </div>
          </Tile>

          <Tile span="3" title="How the month is loaded" note="Dated sends a week, this month, so a week carrying four sends is visible before it arrives.">
            <PillMeter
              label={inMonth.length + " dated sends in " + new Date(monthAt).toLocaleDateString("en-GB", { month: "long" })}
              parts={[0, 1, 2, 3, 4].map((weekIndex) => {
                const count = inMonth.filter((e) => Math.floor((new Date(e.at).getDate() - 1) / 7) === weekIndex).length;
                return { key: "w" + weekIndex, percent: (count / Math.max(1, inMonth.length)) * 100, tone: weekIndex % 2 ? "soft" : undefined };
              })}
              foot="Alternating shades are consecutive weeks — a single wide band means one week is carrying the month." />
            <KeyValues rows={[0, 1, 2, 3, 4].map((weekIndex) => ({
              label: "Week " + (weekIndex + 1),
              value: inMonth.filter((e) => Math.floor((new Date(e.at).getDate() - 1) / 7) === weekIndex).length + " sends",
            })).filter((row) => row.value !== "0 sends")} />
          </Tile>
        </Tiles>
      </>
    );
  }

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