/**
 * Pages Function: POST /api/bug-report — explicit-consent bug reports.
 * GET /api/bug-report?list=1 | ?id=… — owner retrieval (Bearer BUG_REPORT_TOKEN).
 *
 * KV binding (wrangler.toml):
 *   [[kv_namespaces]]
 *   binding = "BUG_REPORTS"
 *   id = "<from: npx wrangler kv namespace create BUG_REPORTS>"
 *
 * Secret (once):
 *   npx wrangler pages secret put BUG_REPORT_TOKEN
 *
 * On missing BUG_REPORTS binding → 503 {"error":"reporting unavailable"}.
 */
import {
  BUG_REPORT_MAX_BYTES,
  validateBugReportBody,
} from '../_lib/bugReport';

interface Env {
  BUG_REPORTS?: KVNamespace;
  BUG_REPORT_TOKEN?: string;
}

type PagesContext = {
  request: Request;
  env: Env;
};

const JSON_HDR = { 'content-type': 'application/json; charset=utf-8' };

function json(status: number, body: unknown): Response {
  return new Response(JSON.stringify(body), { status, headers: JSON_HDR });
}

function unauthorized(): Response {
  return json(401, { error: 'unauthorized' });
}

function requireOwner(request: Request, env: Env): boolean {
  const token = env.BUG_REPORT_TOKEN;
  if (!token) return false;
  const h = request.headers.get('Authorization') || '';
  if (!h.startsWith('Bearer ')) return false;
  return h.slice(7) === token;
}

function newReportId(): string {
  const iso = new Date().toISOString();
  const uuid8 = crypto.randomUUID().replace(/-/g, '').slice(0, 8);
  return `br:${iso}:${uuid8}`;
}

export const onRequestPost = async (context: PagesContext): Promise<Response> => {
  const { request, env } = context;
  if (!env.BUG_REPORTS) {
    return json(503, { error: 'reporting unavailable' });
  }

  const ct = request.headers.get('content-type') || '';
  if (!ct.toLowerCase().includes('application/json')) {
    return json(415, { error: 'JSON only' });
  }

  const rawText = await request.text();
  if (new TextEncoder().encode(rawText).byteLength > BUG_REPORT_MAX_BYTES) {
    return json(413, { error: 'payload exceeds 2 MB' });
  }

  let parsed: unknown;
  try {
    parsed = JSON.parse(rawText);
  } catch {
    return json(400, { error: 'invalid JSON' });
  }

  const v = validateBugReportBody(parsed);
  if (!v.ok) return json(400, { error: v.error });

  const id = newReportId();
  const stored = {
    id,
    receivedAt: new Date().toISOString(),
    ...v.body,
  };
  await env.BUG_REPORTS.put(id, JSON.stringify(stored));
  return json(201, { id });
};

export const onRequestGet = async (context: PagesContext): Promise<Response> => {
  const { request, env } = context;
  if (!env.BUG_REPORTS) {
    return json(503, { error: 'reporting unavailable' });
  }
  if (!requireOwner(request, env)) return unauthorized();

  const url = new URL(request.url);
  const list = url.searchParams.get('list');
  const id = url.searchParams.get('id');

  if (list === '1') {
    const listed = await env.BUG_REPORTS.list({ prefix: 'br:', limit: 200 });
    const keys = listed.keys
      .map(k => k.name)
      .sort()
      .reverse();
    return json(200, { keys, count: keys.length });
  }

  if (id) {
    if (!id.startsWith('br:')) return json(400, { error: 'invalid id' });
    const raw = await env.BUG_REPORTS.get(id);
    if (!raw) return json(404, { error: 'not found' });
    try {
      return json(200, JSON.parse(raw));
    } catch {
      return json(200, { id, raw });
    }
  }

  return json(400, { error: 'pass ?list=1 or ?id=…' });
};
