---
import AppLayout from '../../layouts/AppLayout.astro';
import Avatar from '../../components/Avatar.astro';
import {
  getDispatchWithPoll, getAdjacentDispatches,
  getPulseById, castOrChangeVote, recordActivity, countCabMembers,
} from '../../lib/db';
import {
  parseDispatchSlug, dispatchSlug, dispatchKindLabel,
  dispatchKindPigment, roleLabel,
} from '../../lib/format';
import { renderMd } from '../../lib/markdown';

const user = Astro.locals.user;
const slugParam = Astro.params.slug ?? '';
const id = parseDispatchSlug(slugParam);

if (!id) return Astro.redirect('/dispatches');

// Vote POST — handled before main render so we can refresh state
if (Astro.request.method === 'POST') {
  const data = await Astro.request.formData();
  const action = String(data.get('action') ?? '');
  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(Astro.url.pathname);
  }
}

const d = getDispatchWithPoll(id, user.id);
if (!d || d.status !== 'published') return Astro.redirect('/dispatches');

// Canonical-redirect when the slug changes after a rename — id is the authority
const canonical = dispatchSlug(d);
if (slugParam !== canonical) return Astro.redirect(`/dispatches/${canonical}`);

const totalMembers = countCabMembers();
const { prev, next } = getAdjacentDispatches(d.id);

function closeDayLabel(closesAt: string): string {
  const parsed = closesAt.includes('T') ? new Date(closesAt) : new Date(closesAt.replace(' ', 'T') + 'Z');
  return new Intl.DateTimeFormat('en-GB', { weekday: 'long', timeZone: 'Europe/Copenhagen' }).format(parsed);
}

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(iso: string): string {
  return new Intl.DateTimeFormat('en-GB', {
    day: 'numeric', month: 'long', year: 'numeric', timeZone: 'Europe/Copenhagen',
  }).format(parseUtc(iso));
}

const bodyHtml = renderMd(d.body);
---
<AppLayout title={d.title} user={user}>
  <article class="page">

    <a href="/dispatches" class="section-link back-link">← All dispatches</a>

    <header class="head">
      <div class="head-meta">
        <span class="kind-pill" style={`--pill: ${dispatchKindPigment(d.kind)}`}>
          {dispatchKindLabel(d.kind)}
        </span>
        <time class="head-date label-sm" datetime={d.published_at ?? d.created_at}>
          {fmt(d.published_at ?? d.created_at)}
        </time>
      </div>

      <h1 class="title">{d.title}</h1>

      <div class="byline">
        <Avatar id={d.author_id} name={d.author_name} size={32} />
        <div class="byline-text">
          <span class="byline-name">{d.author_name}</span>
          <span class="byline-role label-sm">{d.author_title ?? roleLabel(d.author_role)}</span>
        </div>
      </div>
    </header>

    <div class="body prose" set:html={bodyHtml} />

    {d.poll && (
      <aside class="inline-poll" aria-label="Poll attached to this dispatch">
        <p class="inline-poll-question">{d.poll.question}</p>
        <form method="POST" class="inline-poll-options" novalidate>
          <input type="hidden" name="action" value="vote" />
          <input type="hidden" name="pulse_id" value={d.poll.id} />
          {d.poll.options.map((opt, i) => {
            const hasVoted = d.poll!.my_vote !== null;
            const chosen = d.poll!.my_vote === i;
            const closed = d.poll!.status !== 'open';
            const count = d.poll!.votes_by_option[i] ?? 0;
            const pct = d.poll!.votes_total > 0 ? (count / d.poll!.votes_total) * 100 : 0;
            const letter = String.fromCharCode(65 + i);
            return (
              <button
                type="submit"
                name="option_index"
                value={i}
                class:list={['inline-poll-option', { chosen, closed }]}
                disabled={closed && !chosen}
                aria-pressed={chosen}
              >
                <span class="inline-poll-letter">{letter}</span>
                <span class="inline-poll-text">{opt}</span>
                {hasVoted && (
                  <span class="inline-poll-pct">{pct.toFixed(0)}%</span>
                )}
                {hasVoted && (
                  <span class="inline-poll-bar" aria-hidden="true">
                    <span class="inline-poll-bar-fill" style={`width:${pct.toFixed(1)}%`}></span>
                  </span>
                )}
              </button>
            );
          })}
        </form>
        <p class="inline-poll-count">
          {d.poll.votes_total} of {totalMembers} have weighed in
          {d.poll.status === 'open'
            ? ` · closes ${closeDayLabel(d.poll.closes_at)}`
            : ' · closed'}
        </p>
      </aside>
    )}

    <hr class="divider" />

    <nav class="adjacent" aria-label="Adjacent dispatches">
      {prev ? (
        <a class="adj-card adj-prev" href={`/dispatches/${dispatchSlug(prev)}`}>
          <span class="adj-direction label-sm">← Previous</span>
          <span class="adj-kind-pill" style={`--pill: ${dispatchKindPigment(prev.kind)}`}>
            {dispatchKindLabel(prev.kind)}
          </span>
          <span class="adj-title">{prev.title}</span>
        </a>
      ) : (
        <span class="adj-empty"></span>
      )}
      {next ? (
        <a class="adj-card adj-next" href={`/dispatches/${dispatchSlug(next)}`}>
          <span class="adj-direction label-sm">Next →</span>
          <span class="adj-kind-pill" style={`--pill: ${dispatchKindPigment(next.kind)}`}>
            {dispatchKindLabel(next.kind)}
          </span>
          <span class="adj-title">{next.title}</span>
        </a>
      ) : (
        <span class="adj-empty"></span>
      )}
    </nav>

  </article>
</AppLayout>

<style>
  .page {
    padding: var(--space-12) var(--space-20) var(--space-16);
    max-width: 720px;
    margin: 0 auto;
    display: flex;
    flex-direction: column;
    gap: var(--space-6);
  }

  .back-link { align-self: flex-start; }

  .head { display: flex; flex-direction: column; gap: var(--space-4); }

  .head-meta {
    display: flex;
    align-items: center;
    gap: var(--space-3);
  }
  .kind-pill {
    background: color-mix(in oklab, var(--pill) 14%, transparent);
    color: var(--pill);
    padding: 3px 12px;
    border-radius: 999px;
    font-family: var(--font-sans);
    font-size: var(--text-label-sm);
    letter-spacing: var(--tracking-wide);
    font-weight: 600;
  }
  .head-date {
    color: var(--on-surface-muted);
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
  }

  .title {
    font-family: var(--font-serif);
    font-weight: 400;
    font-size: 2rem;
    line-height: 1.2;
    letter-spacing: var(--tracking-tight);
    color: var(--on-surface);
    margin: 0;
  }

  .byline {
    display: flex;
    align-items: center;
    gap: var(--space-3);
  }
  .byline-text { display: flex; flex-direction: column; gap: 2px; }
  .byline-name { font-weight: 600; color: var(--on-surface); }
  .byline-role {
    color: var(--on-surface-muted);
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
  }

  .body {
    font-size: var(--text-body-lg);
    line-height: 1.7;
    color: var(--on-surface);
  }
  .body :global(p) { margin: 0 0 var(--space-4); }
  .body :global(h2) {
    font-family: var(--font-serif);
    font-weight: 400;
    font-size: 1.5rem;
    margin: var(--space-6) 0 var(--space-3);
  }
  .body :global(h3) {
    font-family: var(--font-serif);
    font-weight: 400;
    font-size: 1.25rem;
    margin: var(--space-5) 0 var(--space-2);
  }
  .body :global(blockquote) {
    border-left: 2px solid color-mix(in oklab, var(--pigment-terracotta) 40%, transparent);
    padding-left: var(--space-4);
    color: var(--on-surface-variant);
    margin: var(--space-5) 0;
  }
  .body :global(code) {
    font-family: var(--font-mono);
    font-size: 0.9em;
    background: var(--surface-container);
    padding: 0.15em 0.4em;
    border-radius: var(--radius-sm);
  }
  .body :global(ul), .body :global(ol) {
    padding-left: var(--space-5);
    margin: 0 0 var(--space-4);
  }

  .divider {
    border: none;
    height: 0.5px;
    background: var(--surface-card-border);
    margin: var(--space-6) 0 0;
  }

  /* ── Inline poll attached to the dispatch ──────────────────────── */
  .inline-poll {
    margin-top: var(--space-7);
    background: var(--surface-card);
    border: 0.5px solid var(--surface-card-border);
    border-radius: var(--radius-lg);
    padding: var(--space-6);
    display: flex;
    flex-direction: column;
    gap: var(--space-4);
  }
  .inline-poll-question {
    font-family: var(--font-serif);
    font-weight: 400;
    font-size: 1.25rem;
    line-height: 1.3;
    color: var(--on-surface);
    margin: 0;
  }
  .inline-poll-options {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
  }
  .inline-poll-option {
    position: relative;
    display: flex;
    align-items: center;
    gap: var(--space-3);
    padding: var(--space-3) var(--space-4);
    background: var(--background);
    border: 0.5px solid var(--surface-card-border);
    border-radius: var(--radius-md);
    font-family: var(--font-sans);
    font-size: var(--text-body-md);
    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);
    overflow: hidden;
  }
  .inline-poll-option:hover:not(.closed) { border-color: var(--outline); }
  .inline-poll-option.chosen {
    border-color: var(--pigment-terracotta);
    background: color-mix(in oklab, var(--pigment-terracotta) 6%, var(--surface-card));
  }
  .inline-poll-option.closed:not(.chosen) {
    cursor: default;
    color: var(--on-surface-variant);
  }
  .inline-poll-pct {
    margin-left: auto;
    font-family: var(--font-sans);
    font-size: var(--text-label-sm);
    font-weight: 600;
    letter-spacing: var(--tracking-wider);
    color: var(--on-surface-variant);
    font-variant-numeric: tabular-nums;
  }
  .inline-poll-option.chosen .inline-poll-pct { color: var(--pigment-terracotta); }
  .inline-poll-option:disabled { opacity: 0.85; }
  .inline-poll-letter {
    font-weight: 600;
    color: var(--on-surface-muted);
    flex-shrink: 0;
  }
  .inline-poll-option.chosen .inline-poll-letter { color: var(--pigment-terracotta); }
  .inline-poll-text { flex: 1; }
  .inline-poll-bar {
    position: absolute;
    left: 0; right: 0; bottom: 0;
    height: 2px;
    background: var(--surface-container);
  }
  .inline-poll-bar-fill {
    display: block;
    height: 100%;
    background: var(--pigment-terracotta);
    opacity: 0.55;
    transition: width 600ms var(--ease-standard);
  }
  .inline-poll-count {
    color: var(--on-surface-muted);
    font-size: var(--text-label-sm);
    letter-spacing: var(--tracking-wide);
    margin: 0;
  }

  .adjacent {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: var(--space-5);
  }
  .adj-card {
    display: flex;
    flex-direction: column;
    gap: var(--space-2);
    padding: var(--space-5);
    background: var(--surface-card);
    border: 0.5px solid var(--surface-card-border);
    border-radius: var(--radius-lg);
    text-decoration: none;
    border-bottom: 0.5px solid var(--surface-card-border);
    color: inherit;
    transition: transform 300ms var(--ease-standard);
  }
  .adj-card:hover { transform: translateY(-2px); border-bottom-color: var(--surface-card-border); }
  .adj-next { text-align: right; align-items: flex-end; }

  .adj-direction {
    color: var(--on-surface-muted);
    letter-spacing: var(--tracking-wide);
    text-transform: uppercase;
  }
  .adj-kind-pill {
    align-self: flex-start;
    background: color-mix(in oklab, var(--pill) 14%, transparent);
    color: var(--pill);
    padding: 2px 9px;
    border-radius: 999px;
    font-family: var(--font-sans);
    font-size: var(--text-label-sm);
    letter-spacing: var(--tracking-wide);
    font-weight: 600;
  }
  .adj-next .adj-kind-pill { align-self: flex-end; }
  .adj-title {
    font-family: var(--font-serif);
    color: var(--on-surface);
  }
  .adj-empty {} /* placeholder for missing prev/next slot */

  @media (max-width: 640px) {
    .adjacent { grid-template-columns: 1fr; }
    .adj-next { text-align: left; align-items: flex-start; }
    .adj-next .adj-kind-pill { align-self: flex-start; }
  }
</style>
