/**
 * Changelog routes.
 * Public: list published entries. Admin: CRUD all entries.
 */

import type { FastifyInstance } from 'fastify';
import { UnauthorizedError, ForbiddenError, NotFoundError } from '../../lib/errors.js';
import { getRequestProductId, getRequestProductIdForPublic } from '../../lib/request-context.js';
import { CreateChangelogSchema, UpdateChangelogSchema } from './types.js';
import { createEntry, getEntry, listEntries, updateEntry, deleteEntry } from './repository.js';

function requireAdmin(req: { jwtPayload?: { sub: string; role?: string } }): string {
  if (!req.jwtPayload?.sub) throw new UnauthorizedError('Authentication required');
  if (req.jwtPayload.role !== 'admin') throw new ForbiddenError('Admin access required');
  return req.jwtPayload.sub;
}

export async function changelogRoutes(app: FastifyInstance): Promise<void> {
  // ── Public: List published changelog ──────────────────────
  app.get('/changelog', async req => {
    const productId = getRequestProductIdForPublic(req);
    return listEntries(productId, true);
  });

  // ── Public: Get single entry ──────────────────────────────
  app.get<{ Params: { id: string } }>('/changelog/:id', async req => {
    const productId = getRequestProductIdForPublic(req);
    const entry = await getEntry(req.params.id, productId);
    if (!entry || !entry.published) throw new NotFoundError('Changelog entry not found');
    return entry;
  });

  // ── Admin: List all entries (including drafts) ────────────
  app.get('/admin/changelog', async req => {
    requireAdmin(req);
    const productId = getRequestProductId(req);
    return listEntries(productId, false);
  });

  // ── Admin: Create entry ───────────────────────────────────
  app.post('/admin/changelog', async (req, reply) => {
    requireAdmin(req);
    const productId = getRequestProductId(req);
    const input = CreateChangelogSchema.parse(req.body);
    const entry = await createEntry(productId, input);
    reply.status(201);
    return entry;
  });

  // ── Admin: Update entry ───────────────────────────────────
  app.put<{ Params: { id: string } }>('/admin/changelog/:id', async req => {
    requireAdmin(req);
    const productId = getRequestProductId(req);
    const updates = UpdateChangelogSchema.parse(req.body);
    const entry = await updateEntry(req.params.id, productId, updates);
    if (!entry) throw new NotFoundError('Changelog entry not found');
    return entry;
  });

  // ── Admin: Delete entry ───────────────────────────────────
  app.delete<{ Params: { id: string } }>('/admin/changelog/:id', async (req, reply) => {
    requireAdmin(req);
    const productId = getRequestProductId(req);
    const ok = await deleteEntry(req.params.id, productId);
    if (!ok) throw new NotFoundError('Changelog entry not found');
    reply.status(204);
  });
}
