/**
 * Public unsubscribe endpoint (PR-19, May 2026).
 *
 * Two-step flow (audit3 react-doctor follow-up):
 *   GET  /api/status/unsubscribe?token=<64-hex>  → renders an HTML
 *        confirmation page with a POST form. No side effects.
 *   POST /api/status/unsubscribe   (form-encoded token)
 *        → actually deletes the subscriber row, then redirects to
 *          /status?unsubscribed=1.
 *
 * Why the two-step pattern: email clients (Gmail, Outlook, modern
 * spam filters) routinely PREFETCH links in messages to scan for
 * malware / generate previews. A single-step GET-deletes pattern
 * silently unsubscribed users every time their inbox was scanned.
 * RFC 8058 ("one-click unsubscribe") also expects POST.
 *
 * Idempotency: unknown tokens render the same confirm page so an
 * attacker cannot enumerate which tokens exist. The POST is also
 * idempotent — repeating it on an already-deleted row no-ops.
 */
import { NextRequest, NextResponse } from 'next/server';
import { StatusSubscriberService } from '@/lib/services/status-subscriber.service';

export const dynamic = 'force-dynamic';

function confirmPageHtml(token: string): string {
    // Escape the token before interpolating into the HTML even though
    // we validate it as hex-only below — defence in depth.
    const safeToken = token.replace(/[^a-f0-9]/g, '');
    return `<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width,initial-scale=1">
  <meta name="robots" content="noindex,nofollow">
  <title>Confirm unsubscribe — Uptime Sentinel</title>
  <style>
    body { font-family: system-ui, sans-serif; max-width: 480px; margin: 4rem auto; padding: 1rem; color: #1e293b; }
    h1 { font-size: 1.25rem; margin-bottom: 0.5rem; }
    p { color: #64748b; line-height: 1.6; }
    form { margin-top: 1.5rem; }
    button { background: #ef4444; color: #fff; border: 0; padding: 0.6rem 1.2rem; border-radius: 6px; font-size: 1rem; cursor: pointer; }
    button:hover { background: #dc2626; }
    a { color: #64748b; margin-left: 1rem; }
  </style>
</head>
<body>
  <h1>Unsubscribe from Uptime Sentinel status alerts?</h1>
  <p>Click the button to confirm. You'll stop receiving incident emails from this status page.</p>
  <form method="POST" action="/api/status/unsubscribe">
    <input type="hidden" name="token" value="${safeToken}">
    <button type="submit">Unsubscribe</button>
    <a href="/status">Cancel</a>
  </form>
</body>
</html>`;
}

// audit3-followup: this GET has no side effects post-refactor — it only
// returns the HTML confirm-page string. The static analyser appears to
// flag any GET in this file because the same module also exports a
// state-mutating POST; suppress here since the GET itself is now
// side-effect-free by construction.
// react-doctor-disable-next-line react-doctor/nextjs-no-side-effect-in-get-handler
export async function GET(req: NextRequest) {
    const token = req.nextUrl.searchParams.get('token') ?? '';
    // Always render the same confirm page regardless of token validity;
    // the actual validity check happens on POST so we never leak which
    // tokens exist via the GET response.
    return new Response(confirmPageHtml(token), {
        headers: { 'Content-Type': 'text/html; charset=utf-8' },
    });
}

export async function POST(req: NextRequest) {
    const form = await req.formData();
    const token = String(form.get('token') ?? '');
    const service = new StatusSubscriberService();
    await service.unsubscribe(token);
    // Same response for ok + unknown — don't leak token validity.
    const target = new URL('/status?unsubscribed=1', req.url);
    return NextResponse.redirect(target, { status: 303 });
}
