---
import AppLayout from '../layouts/AppLayout.astro';
import Avatar from '../components/Avatar.astro';
import EventHeroCard from '../components/EventHeroCard.astro';
import RoadmapCarousel from '../components/RoadmapCarousel.astro';
import {
  getUpcomingEvents, getEventBySlug, getEventAttendees,
  getUserRsvp, setEventRsvp, recordActivity,
  getAllRoadmapItems, getLatestPublishedDispatches, getDispatchWithPoll,
  getAllCabMembers, getPulseById, castOrChangeVote,
} from '../lib/db';
import {
  timeOfDay, relativeTime,
  eventKindLabel,
  dispatchSlug, dispatchKindLabel, dispatchKindPigment, dispatchLongPreview,
} from '../lib/format';

const user = Astro.locals.user;

// ── POST: RSVP + Vote ──────────────────────────────────────────────
if (Astro.request.method === 'POST') {
  const data = await Astro.request.formData();
  const action = String(data.get('action') ?? '');

  if (action === 'rsvp') {
    const slug = String(data.get('event_slug') ?? '');
    const status = String(data.get('status') ?? '') as 'yes' | 'no' | 'interested';
    if (slug && ['yes', 'no', 'interested'].includes(status)) {
      const ev = getEventBySlug(slug);
      if (ev) {
        setEventRsvp(user.id, slug, status);
        recordActivity(user.id, 'rsvped', 'event', ev.id);
      }
    }
    return Astro.redirect('/pulse');
  }

  if (action === 'vote') {
    const pulseId = Number(data.get('pulse_id'));
    const optionIndex = Number(data.get('option_index'));
    const target = getPulseById(pulseId);
    if (target && target.status === 'open' && Number.isInteger(optionIndex)
        && optionIndex >= 0 && optionIndex < target.options.length) {
      const wasNew = castOrChangeVote(pulseId, user.id, optionIndex);
      if (wasNew) recordActivity(user.id, 'voted', 'pulse', pulseId);
    }
    return Astro.redirect('/pulse');
  }
}

// ── Greeting ───────────────────────────────────────────────────────
const firstName = user.name.split(' ')[0];
const greetingPrefix = `Good ${timeOfDay()}, `;          // "Good morning, "

const memberNumberLabel = user.member_number != null
  ? `MEMBER · ${String(user.member_number).padStart(3, '0')}`
  : null;

// ── Events ─────────────────────────────────────────────────────────
const upcoming = getUpcomingEvents(20);
const hero = upcoming.find(e => e.kind !== 'office_hours') ?? upcoming[0] ?? null;
const comingUp = upcoming.filter(e => e.id !== hero?.id).slice(0, 4);

function parseUtc(s: string): Date {
  if (/T.*[Zz]$/.test(s) || /[+-]\d{2}:?\d{2}$/.test(s)) return new Date(s);
  return new Date(s.replace(' ', 'T') + 'Z');
}
function fmt(part: Intl.DateTimeFormatOptions, iso: string): string {
  return new Intl.DateTimeFormat('en-GB', { ...part, timeZone: 'Europe/Copenhagen' }).format(parseUtc(iso));
}
const dayNum     = (iso: string) => fmt({ day: 'numeric' }, iso);
const weekday    = (iso: string) => fmt({ weekday: 'short' }, iso).toUpperCase();
const monthShort = (iso: string) => fmt({ month: 'short' }, iso).toUpperCase();
const timeStr    = (iso: string) => fmt({ hour: '2-digit', minute: '2-digit', hour12: false }, iso);

const heroAttendees = hero ? getEventAttendees(hero.slug, 'yes') : [];
const heroConfirmedCount = heroAttendees.length;
const heroMyRsvp = hero ? getUserRsvp(user.id, hero.slug) : null;

// ── Latest from Fenja (featured + 2 minimalist below) ──────────────
const recentDispatches = getLatestPublishedDispatches(3);
const featuredSummary = recentDispatches[0] ?? null;
const featured = featuredSummary ? getDispatchWithPoll(featuredSummary.id, user.id) : null;
const moreDispatches = recentDispatches.slice(1, 3);
const featuredPreview = featured ? dispatchLongPreview(featured, 720) : '';

function closeDayLabel(closesAt: string): string {
  return new Intl.DateTimeFormat('en-GB', {
    weekday: 'long', timeZone: 'Europe/Copenhagen',
  }).format(parseUtc(closesAt));
}

// ── Roadmap (all items, admin orders chronologically near→far) ─────
const roadmapItems = getAllRoadmapItems()
  .sort((a, b) => a.display_order - b.display_order || a.id - b.id);

// ── Council ─────────────────────────────────────────────────────────
const members = getAllCabMembers();
---
<AppLayout title="Pulse" user={user}>
  <div class="page">

    <!-- ── Greeting ─────────────────────────────────────────────── -->
    <section class="cascade greeting">
      <div class="greeting-left">
        <h1 class="greeting-line">{greetingPrefix}<em class="greeting-first">{firstName}</em>.</h1>
      </div>
      {memberNumberLabel && (
        <div class="greeting-right">
          <p class="greeting-member">{memberNumberLabel}</p>
          <p class="greeting-circle">Founding circle</p>
        </div>
      )}
    </section>

    <!-- ── Hero event card (--ink) ──────────────────────────────── -->
    <section class="cascade hero-slot" aria-label="Next gathering">
      <EventHeroCard
        event={hero}
        attendees={heroAttendees}
        confirmedCount={heroConfirmedCount}
        myRsvp={heroMyRsvp}
      />
    </section>

    <!-- ── 'Also coming up' strip (plain text on cream) ─────────── -->
    <section class="cascade also-coming-up" aria-label="Also coming up">
      <div class="also-list">
        {comingUp.slice(0, 2).map((ev, i) => (
          <>
            {i > 0 && <span class="also-divider" aria-hidden="true"></span>}
            <div class="also-item">
              <span class="also-day">{dayNum(ev.starts_at)}</span>
              <div class="also-meta-col">
                <span class="also-month-kind">{monthShort(ev.starts_at)} · {eventKindLabel(ev.kind).toUpperCase()}</span>
                <span class="also-title">{ev.title}</span>
              </div>
            </div>
          </>
        ))}
      </div>
      <a href="/events" class="also-link">All gatherings →</a>
    </section>

    <!-- ── Editorial row: dispatch (1.7fr) + pulse (1fr) ─────────── -->
    {featured && (
      <section class="cascade editorial-row" aria-label="Latest from Fenja">

        <article class="dispatch-col">
          <header class="dispatch-byline">
            <Avatar id={featured.author_id} name={featured.author_name} size={26} />
            <span class="dispatch-byline-name">{featured.author_name.split(' ')[0]}</span>
            <span class="dispatch-byline-time">{relativeTime(featured.published_at ?? featured.created_at)}</span>
            <span class="dispatch-kind-pill" style={`--pill: ${dispatchKindPigment(featured.kind)}`}>
              {dispatchKindLabel(featured.kind).toUpperCase()}
            </span>
          </header>

          <h2 class="dispatch-headline">{featured.title}</h2>

          <p class="dispatch-para-lead">{featuredPreview}</p>

          <a href={`/dispatches/${dispatchSlug(featured)}`} class="dispatch-read">Read the full dispatch</a>

          {moreDispatches.length > 0 && (
            <div class="earlier-block">
              <p class="earlier-label">Earlier</p>
              <ul class="earlier-list">
                {moreDispatches.map(d => (
                  <li class="earlier-row">
                    <a href={`/dispatches/${dispatchSlug(d)}`} class="earlier-link">
                      <span class="earlier-title">{d.title}</span>
                      <span class="earlier-meta">{dispatchKindLabel(d.kind).toUpperCase()} · {Math.max(1, Math.round((Date.now() - new Date((d.published_at ?? d.created_at).replace(' ', 'T') + 'Z').getTime()) / 86400000))}D</span>
                    </a>
                  </li>
                ))}
              </ul>
            </div>
          )}
        </article>

        {featured.poll && (
          <aside class="pulse-col" aria-label="This week's pulse">
            <p class="pulse-eyebrow"><span class="pulse-eyebrow-dot" aria-hidden="true"></span>Pulse Vote</p>
            <p class="pulse-question">{featured.poll.question}</p>
            <p class="pulse-status">
              {featured.poll.my_vote === null
                ? <>Vote to see how the council weighs in · Closes {closeDayLabel(featured.poll.closes_at).toUpperCase()}</>
                : <>{featured.poll.votes_total} of {members.length} voted · Closes {closeDayLabel(featured.poll.closes_at).toUpperCase()} · Click to change</>}
            </p>

            <form method="POST" class="pulse-options" novalidate>
              <input type="hidden" name="action" value="vote" />
              <input type="hidden" name="pulse_id" value={featured.poll.id} />
              {featured.poll.options.map((opt, i) => {
                const hasVoted = featured.poll!.my_vote !== null;
                const chosen = featured.poll!.my_vote === i;
                const closed = featured.poll!.status !== 'open';
                const count = featured.poll!.votes_by_option[i] ?? 0;
                const pct = featured.poll!.votes_total > 0 ? (count / featured.poll!.votes_total) * 100 : 0;
                const letter = String.fromCharCode(65 + i);
                return (
                  <button
                    type="submit"
                    name="option_index"
                    value={i}
                    class:list={['pulse-option', { chosen, closed }]}
                    disabled={closed && !chosen}
                    aria-pressed={chosen}
                  >
                    <span class="pulse-option-letter">{letter}</span>
                    <span class="pulse-option-text">{opt}</span>
                    {hasVoted && (
                      <span class="pulse-option-pct" aria-label={`${pct.toFixed(0)} percent`}>{pct.toFixed(0)}%</span>
                    )}
                  </button>
                );
              })}
            </form>
          </aside>
        )}
      </section>
    )}

    <!-- ── Roadmap — horizontal snap-scrolling carousel ─────────── -->
    {roadmapItems.length > 0 && (
      <div class="cascade roadmap-wrap">
        <RoadmapCarousel items={roadmapItems} />
      </div>
    )}

    <!-- ── Council — auto-scrolling marquee, all members ───────── -->
    {members.length > 0 && (
      <section class="cascade council-section" aria-label="The council">
        <header class="council-header">
          <h2 class="council-title">The <em>council.</em></h2>
          <a href="/members" class="council-all">See who our council is made up of →</a>
        </header>

        <div class="council-marquee" aria-roledescription="carousel">
          <ul class="council-marquee-track" style={`--marquee-duration: ${Math.max(28, members.length * 6)}s;`}>
            {[...members, ...members].map((m, i) => (
              <li class="council-tile" aria-hidden={i >= members.length ? 'true' : undefined}>
                <Avatar id={m.id} name={m.name} size={38} />
                <div class="council-tile-text">
                  <span class="council-tile-name">{m.name}</span>
                  {m.title && <span class="council-tile-title">{m.title}</span>}
                  <span class="council-tile-org">{m.organisation}</span>
                </div>
              </li>
            ))}
          </ul>
        </div>
      </section>
    )}

  </div>
</AppLayout>

<style>
  .page {
    padding: 40px 36px 80px;
    max-width: var(--content-max);
    margin: 0 auto;
    display: flex;
    flex-direction: column;
  }

  /* Per-section spacing table. More air between sections than before
     (96px between editorial / roadmap / council); editorial-row internal
     dispatch → 'Earlier' gap stays tight at the original 48px because
     they're the same story. */
  .greeting       { margin-top: 64px;  }   /* below nav */
  .hero-slot      { margin-top: 80px;  }   /* greeting → hero */
  .also-coming-up { margin-top: 18px;  }   /* hero → also (tight; pair) */
  .editorial-row  { margin-top: 96px;  }   /* also → editorial */
  .roadmap-wrap   { margin-top: 96px;  }   /* editorial → roadmap */
  .council-section{ margin-top: 96px;  }   /* roadmap → council */

  /* ── Cascade entry (first paint only) ─────────────────────────── */
  .cascade {
    opacity: 0;
    transform: translateY(10px);
    animation: cascade-in 650ms var(--ease-standard) forwards;
  }
  .cascade:nth-child(1) { animation-delay: 0ms;   }
  .cascade:nth-child(2) { animation-delay: 100ms; }
  .cascade:nth-child(3) { animation-delay: 200ms; }
  .cascade:nth-child(4) { animation-delay: 300ms; }
  .cascade:nth-child(5) { animation-delay: 400ms; }
  @keyframes cascade-in { to { opacity: 1; transform: translateY(0); } }
  @media (prefers-reduced-motion: reduce) {
    .cascade { opacity: 1; transform: none; animation: none; }
  }

  /* ── Greeting (two-column) ────────────────────────────────────── */
  .greeting {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-6);
    align-items: end;
  }
  .greeting-left {
    display: flex;
    flex-direction: column;
    max-width: 30rem;
  }
  .greeting-right {
    display: flex;
    flex-direction: column;
    align-items: flex-end;
    gap: 6px;
  }
  .greeting-line {
    font-family: var(--font-serif);
    font-weight: 400;
    font-size: 36px;
    line-height: 1.05;
    letter-spacing: var(--tracking-tight);
    color: var(--on-surface);
    margin: 0;
  }
  .greeting-first { font-style: italic; }
  .greeting-member {
    font-family: var(--font-sans);
    font-size: 11px;
    letter-spacing: var(--tracking-wider);
    text-transform: uppercase;
    color: var(--on-surface-variant);
    margin: 0;
  }
  .greeting-circle {
    font-family: var(--font-serif);
    font-size: 14px;
    color: var(--on-surface);
    margin: 0;
  }

  @media (max-width: 720px) {
    .greeting { grid-template-columns: 1fr; align-items: start; }
    .greeting-right { align-items: flex-start; }
  }

  /* ── 'Also coming up' strip (plain text on cream) ─────────────── */
  .also-coming-up {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 4px 0;
    gap: var(--space-5);
  }
  .also-list {
    display: flex;
    align-items: center;
    gap: 18px;
    min-width: 0;
  }
  .also-divider {
    display: inline-block;
    width: 1px;
    height: 28px;
    background: rgba(0, 0, 0, 0.08);
    transform: scaleX(1);
  }
  .also-item {
    display: flex;
    align-items: center;
    gap: 12px;
  }
  .also-day {
    font-family: var(--font-serif);
    font-weight: 400;
    font-size: 22px;
    line-height: 1;
    color: var(--on-surface);
  }
  .also-meta-col {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
  }
  .also-month-kind {
    font-family: var(--font-sans);
    font-size: 9px;
    letter-spacing: var(--tracking-wider);
    text-transform: uppercase;
    color: var(--on-surface-variant);
  }
  .also-title {
    font-size: 13px;
    color: var(--on-surface);
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
    max-width: 16rem;
  }
  .also-link {
    font-family: var(--font-sans);
    font-size: 11px;
    letter-spacing: var(--tracking-wider);
    text-transform: uppercase;
    color: var(--pigment-terracotta);
    text-decoration: none;
    border-bottom: none;
  }
  .also-link:hover { opacity: 0.8; border-bottom: none; }

  /* ── Editorial row: dispatch (1.7fr) + pulse (1fr) ────────────── */
  .editorial-row {
    display: grid;
    grid-template-columns: 1.7fr 1fr;
    gap: 56px;
    align-items: start;
  }

  /* Dispatch column */
  .dispatch-col { display: flex; flex-direction: column; gap: var(--space-3); }
  .dispatch-byline {
    display: flex;
    align-items: center;
    gap: 10px;
  }
  .dispatch-byline-name {
    font-family: var(--font-sans);
    font-size: 12px;
    font-weight: 600;
    color: var(--on-surface);
  }
  .dispatch-byline-time {
    font-family: var(--font-sans);
    font-size: 11px;
    color: var(--on-surface-variant);
  }
  .dispatch-kind-pill {
    background: color-mix(in oklab, var(--pill) 14%, transparent);
    color: var(--pill);
    padding: 2px 8px;
    border-radius: 3px;
    font-family: var(--font-sans);
    font-size: 9px;
    letter-spacing: var(--tracking-wider);
    font-weight: 600;
    margin-left: auto;
  }
  .dispatch-headline {
    font-family: var(--font-serif);
    font-weight: 400;
    font-size: 32px;
    line-height: 1.15;
    color: var(--on-surface);
    margin: 8px 0 0;
    letter-spacing: var(--tracking-snug);
  }
  .dispatch-para-lead {
    margin: var(--space-2) 0 0;
    font-size: 14px;
    line-height: 1.7;
    color: var(--on-surface);
  }
  .dispatch-read {
    margin-top: var(--space-2);
    align-self: flex-start;
    font-family: var(--font-sans);
    font-size: 11px;
    letter-spacing: var(--tracking-wider);
    text-transform: uppercase;
    color: var(--pigment-terracotta);
    text-decoration: none;
    border-bottom: 1px solid var(--pigment-terracotta);
    padding-bottom: 1px;
  }
  .dispatch-read:hover { opacity: 0.78; border-bottom: 1px solid var(--pigment-terracotta); }

  .earlier-block {
    margin-top: 48px;
    padding-top: 28px;
    border-top: 0.5px solid rgba(0, 0, 0, 0.08);
    display: flex;
    flex-direction: column;
    gap: 14px;
  }
  .earlier-label {
    font-family: var(--font-sans);
    font-size: 11px;
    letter-spacing: var(--tracking-wider);
    text-transform: uppercase;
    color: var(--on-surface-variant);
    margin: 0;
  }
  .earlier-list {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    flex-direction: column;
    gap: 14px;
  }
  .earlier-link {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
    gap: 16px;
    color: var(--on-surface);
    text-decoration: none;
    border-bottom: none;
  }
  .earlier-link:hover { border-bottom: none; opacity: 0.7; }
  .earlier-title {
    font-family: var(--font-serif);
    font-size: 15px;
    line-height: 1.3;
  }
  .earlier-meta {
    font-family: var(--font-sans);
    font-size: 10px;
    letter-spacing: var(--tracking-wider);
    text-transform: uppercase;
    color: var(--on-surface-variant);
    white-space: nowrap;
  }

  /* Pulse column */
  .pulse-col { display: flex; flex-direction: column; gap: 14px; }
  .pulse-eyebrow {
    display: flex;
    align-items: center;
    gap: 8px;
    font-family: var(--font-sans);
    font-size: 10px;
    letter-spacing: var(--tracking-wider);
    text-transform: uppercase;
    color: var(--pigment-terracotta);
    margin: 0;
  }
  .pulse-eyebrow-dot {
    width: 5px;
    height: 5px;
    border-radius: 50%;
    background: var(--pigment-terracotta);
  }
  .pulse-question {
    font-family: var(--font-serif);
    font-weight: 400;
    font-size: 22px;
    line-height: 1.25;
    color: var(--on-surface);
    margin: 0;
  }
  .pulse-status {
    font-family: var(--font-sans);
    font-size: 11px;
    letter-spacing: var(--tracking-wider);
    text-transform: uppercase;
    color: var(--on-surface-variant);
    margin: 0;
  }
  .pulse-options {
    display: flex;
    flex-direction: column;
    gap: 6px;
    margin-top: 6px;
  }
  .pulse-option {
    display: flex;
    align-items: center;
    gap: 8px;
    padding: 10px 14px;
    background: transparent;
    border: none;
    border-left: 2px solid rgba(0, 0, 0, 0.1);
    font-family: var(--font-sans);
    font-size: 13px;
    color: var(--on-surface);
    text-align: left;
    cursor: pointer;
    transition: border-color var(--duration-fast) var(--ease-standard),
                background var(--duration-fast) var(--ease-standard);
  }
  .pulse-option:hover:not(.closed) { border-left-color: rgba(0, 0, 0, 0.25); }
  .pulse-option.chosen {
    border-left-color: var(--pigment-terracotta);
    background: rgba(185, 107, 88, 0.05);
  }
  .pulse-option.closed:not(.chosen) {
    cursor: default;
    color: var(--on-surface-variant);
  }
  .pulse-option:disabled { opacity: 0.85; }
  .pulse-option-letter {
    color: var(--on-surface-variant);
    font-family: var(--font-sans);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: var(--tracking-wider);
    text-transform: uppercase;
    margin-right: 8px;
    flex-shrink: 0;
  }
  .pulse-option.chosen .pulse-option-letter { color: var(--pigment-terracotta); }
  .pulse-option-text { flex: 1; }
  /* Percentage badge — only rendered once the viewer has voted. Pulled to
     the right via margin-left:auto so option-text can still flex. */
  .pulse-option-pct {
    margin-left: auto;
    font-family: var(--font-sans);
    font-size: 10px;
    font-weight: 600;
    letter-spacing: var(--tracking-wider);
    color: var(--on-surface-variant);
    font-variant-numeric: tabular-nums;
  }
  .pulse-option.chosen .pulse-option-pct { color: var(--pigment-terracotta); }

  /* ── Council — section framing matches the roadmap carousel ──── */
  .council-section {
    display: flex;
    flex-direction: column;
    gap: 24px;
  }
  .council-header {
    display: flex;
    justify-content: space-between;
    align-items: baseline;
  }
  .council-title {
    font-family: var(--font-serif);
    font-weight: 400;
    font-size: 22px;
    line-height: 1.2;
    color: var(--on-surface);
    margin: 0;
  }
  .council-title em { font-style: italic; }
  .council-all {
    font-family: var(--font-sans);
    font-size: 11px;
    letter-spacing: var(--tracking-wider);
    text-transform: uppercase;
    color: var(--pigment-terracotta);
    text-decoration: none;
    border-bottom: none;
  }
  .council-all:hover { opacity: 0.8; border-bottom: none; }

  /* Marquee — list is rendered twice so translateX(-50%) wraps seamlessly.
     The duration is set via --marquee-duration on the inline style so the
     loop speed scales with member count. Paused on hover and for users
     with reduced-motion preferences. */
  .council-marquee {
    position: relative;
    overflow: hidden;
    -webkit-mask-image: linear-gradient(90deg, transparent 0, #000 6%, #000 94%, transparent 100%);
            mask-image: linear-gradient(90deg, transparent 0, #000 6%, #000 94%, transparent 100%);
  }
  .council-marquee-track {
    list-style: none;
    padding: 0;
    margin: 0;
    display: flex;
    gap: 48px;
    width: max-content;
    animation: council-scroll var(--marquee-duration, 40s) linear infinite;
    will-change: transform;
  }
  .council-marquee:hover .council-marquee-track {
    animation-play-state: paused;
  }
  @keyframes council-scroll {
    from { transform: translateX(0);    }
    to   { transform: translateX(-50%); }
  }
  @media (prefers-reduced-motion: reduce) {
    .council-marquee-track { animation: none; }
    .council-marquee {
      overflow-x: auto;
      scrollbar-width: none;
    }
    .council-marquee::-webkit-scrollbar { display: none; }
  }

  .council-tile {
    display: flex;
    align-items: center;
    gap: 12px;
    flex: 0 0 auto;
    min-width: 220px;
  }
  .council-tile-text {
    display: flex;
    flex-direction: column;
    gap: 2px;
    min-width: 0;
  }
  .council-tile-name {
    font-family: var(--font-serif);
    font-weight: 400;
    font-size: 15px;
    line-height: 1.15;
    color: var(--on-surface);
    white-space: nowrap;
  }
  .council-tile-title {
    font-family: var(--font-sans);
    font-size: 11px;
    color: var(--on-surface-variant);
    line-height: 1.35;
    white-space: nowrap;
  }
  .council-tile-org {
    font-family: var(--font-sans);
    font-size: 10px;
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
    color: var(--on-surface-variant);
    white-space: nowrap;
  }

  /* ── Responsive ───────────────────────────────────────────────── */
  @media (max-width: 880px) {
    .editorial-row { grid-template-columns: 1fr; gap: var(--space-8); }
    .also-coming-up { flex-direction: column; align-items: flex-start; gap: var(--space-3); }
  }
</style>
