/**
 * Public status API routes — system-status-page.
 *
 * GET  /api/status                       → StatusPayload (KV-cached, 30s TTL)
 * GET  /api/status/history?days=90       → StatusHistoryPayload
 * POST /api/status/subscribe             → subscribe email (idempotent, 200)
 * GET  /status/unsubscribe?token=...     → unsubscribe email address
 * GET  /status/rss.xml                   → RSS 2.0 feed of recent incidents
 *
 * No auth required on any route; subscribe is rate-limited via RATE_LIMITER_LEAD_FORM.
 */
import { Hono } from 'hono'
import { z } from 'zod'
import { createDb } from '@zync/db/queries'
import {
  getIncidentHistory,
  addSubscriber,
  getSubscriberByToken,
  removeSubscriber,
} from '@zync/db/queries'
import { getCachedStatus } from '../../lib/status-cache'
import type { AppEnv } from '../../types'

const publicStatusRoutes = new Hono<AppEnv>()

// ── GET /api/status ───────────────────────────────────────────────────────────

publicStatusRoutes.get('/', async (c) => {
  const payload = await getCachedStatus(c.env)
  return c.json(payload)
})

// ── GET /api/status/history ───────────────────────────────────────────────────

const HistoryQuery = z.object({
  days: z.coerce.number().int().min(1).max(365).default(90),
})

publicStatusRoutes.get('/history', async (c) => {
  const q = HistoryQuery.safeParse(Object.fromEntries(new URL(c.req.url).searchParams))
  if (!q.success) {
    return c.json({ error: 'Invalid query', details: q.error.flatten() }, 400)
  }

  const db = createDb(c.env)
  const history = await getIncidentHistory(db, q.data.days)
  return c.json(history)
})

// ── POST /api/status/subscribe ────────────────────────────────────────────────

const SubscribeBody = z.object({
  email: z.string().email(),
})

publicStatusRoutes.post('/subscribe', async (c) => {
  // Rate-limit using the existing RATE_LIMITER_LEAD_FORM binding
  const rl = (c.env as unknown as { RATE_LIMITER_LEAD_FORM?: RateLimit }).RATE_LIMITER_LEAD_FORM
  if (rl) {
    const ip = c.req.header('CF-Connecting-IP') ?? 'unknown'
    const outcome = await rl.limit({ key: `status_subscribe:${ip}` })
    if (!outcome.success) {
      return c.json({ error: 'Too many requests' }, 429)
    }
  }

  const parsed = SubscribeBody.safeParse(await c.req.json())
  if (!parsed.success) {
    return c.json({ error: 'Invalid request', details: parsed.error.flatten() }, 400)
  }

  const db = createDb(c.env)
  // addSubscriber is idempotent — silently ignores duplicate emails
  await addSubscriber(db, parsed.data.email)

  // Always return 200 with a neutral message — do not reveal subscription state
  return c.json({ ok: true, message: 'If that email is valid, you will receive status updates.' })
})

// ── GET /status/unsubscribe ───────────────────────────────────────────────────

const UnsubQuery = z.object({
  token: z.string().min(1),
})

publicStatusRoutes.get('/unsubscribe', async (c) => {
  const q = UnsubQuery.safeParse(Object.fromEntries(new URL(c.req.url).searchParams))
  if (!q.success) {
    return c.html(unsubscribeHtml('Invalid or missing unsubscribe token.', false))
  }

  const db = createDb(c.env)
  const sub = await getSubscriberByToken(db, q.data.token)
  if (!sub) {
    return c.html(unsubscribeHtml('This unsubscribe link is invalid or has already been used.', false))
  }

  await removeSubscriber(db, q.data.token)
  return c.html(unsubscribeHtml('You have been unsubscribed from Zync status updates.', true))
})

// ── GET /status/rss.xml ───────────────────────────────────────────────────────

publicStatusRoutes.get('/rss.xml', async (c) => {
  const db = createDb(c.env)
  const history = await getIncidentHistory(db, 90)

  const items = history.incidents
    .map((inc) => {
      const latestUpdate = inc.updates[0]
      const description = latestUpdate
        ? `${latestUpdate.body} (${inc.status})`
        : `Impact: ${inc.impact}. Status: ${inc.status}.`
      const pubDate = new Date(inc.createdAt).toUTCString()
      return `    <item>
      <title>${escapeXml(inc.title)}</title>
      <link>https://zync.is/status</link>
      <guid isPermaLink="false">urn:zync:incident:${inc.id}</guid>
      <pubDate>${pubDate}</pubDate>
      <description>${escapeXml(description)}</description>
    </item>`
    })
    .join('\n')

  const rss = `<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0">
  <channel>
    <title>Zync System Status</title>
    <link>https://zync.is/status</link>
    <description>Real-time and historical Zync system health incidents.</description>
    <language>en</language>
    <lastBuildDate>${new Date().toUTCString()}</lastBuildDate>
${items}
  </channel>
</rss>`

  return new Response(rss, {
    headers: {
      'Content-Type': 'application/rss+xml; charset=utf-8',
      'Cache-Control': 'public, max-age=60',
    },
  })
})

// ── Helpers ───────────────────────────────────────────────────────────────────

function escapeXml(str: string): string {
  return str
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;')
    .replace(/'/g, '&apos;')
}

function unsubscribeHtml(message: string, success: boolean): string {
  const color = success ? 'color:var(--success)' : 'color:var(--danger)'
  return `<!DOCTYPE html>
<html lang="en" class="dark">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>Zync Status — Unsubscribe</title>
  <style>
    :root {
      --bg: oklch(13% 0.035 240);
      --surface: oklch(16% 0.042 240);
      --ink: oklch(95% 0.016 195);
      --line: oklch(24% 0.045 230);
      --accent: oklch(88% 0.16 191);
      --success: oklch(72% 0.16 155);
      --danger: oklch(68% 0.22 25);
    }
    body { font-family: system-ui, sans-serif; background: var(--bg); color: var(--ink);
           display: flex; align-items: center; justify-content: center; min-height: 100vh; margin: 0; }
    .card { background: var(--surface); border: 1px solid var(--line); border-radius: 4px;
            padding: 2rem; max-width: 420px; text-align: center; }
    p { margin: 0.5rem 0; }
  </style>
</head>
<body>
  <div class="card" role="main">
    <p style="${color}" aria-live="polite">${message}</p>
    <p><a href="https://zync.is/status" style="color:var(--accent);text-decoration:underline">View status page</a></p>
  </div>
</body>
</html>`
}

export { publicStatusRoutes }
