/**
 * Tracker items REST endpoints.
 *
 * GET    /items              — list/filter/search items
 * POST   /items              — create item
 * GET    /items/:id          — get single item
 * PUT    /items/:id          — update item
 * PATCH  /items/:id/status   — quick status transition
 * DELETE /items/:id          — delete item
 * GET    /items/stats        — aggregate counts by type/status/priority
 */

import type { FastifyInstance } from 'fastify';
import { getRequestProductId } from '../../lib/request-context.js';
import { BadRequestError, NotFoundError } from '../../lib/errors.js';
import { extractAuth } from '../../lib/auth.js';
import * as repo from './repository.js';
import {
  CreateItemSchema,
  UpdateItemSchema,
  UpdateStatusSchema,
  ListItemsQuerySchema,
  PRIORITY_ORDER,
  type TrackerItemDoc,
} from './types.js';

export async function itemRoutes(app: FastifyInstance) {
  // Stats — must be registered before :id param route
  app.get('/items/stats', async req => {
    const auth = await extractAuth(req);
    const pid = getRequestProductId(req);

    const { items } = await repo.list({
      productId: pid,
      limit: 1000,
      offset: 0,
      sortBy: 'createdAt',
      sortOrder: 'desc',
    });

    const byType: Record<string, number> = {};
    const byStatus: Record<string, number> = {};
    const byPriority: Record<string, number> = {};

    for (const item of items) {
      byType[item.type] = (byType[item.type] || 0) + 1;
      byStatus[item.status] = (byStatus[item.status] || 0) + 1;
      byPriority[item.priority] = (byPriority[item.priority] || 0) + 1;
    }

    return {
      productId: pid,
      total: items.length,
      byType,
      byStatus,
      byPriority,
      requestedBy: auth.sub,
    };
  });

  // List items
  app.get('/items', async req => {
    await extractAuth(req);
    const parsed = ListItemsQuerySchema.safeParse(req.query);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }
    const query = parsed.data;
    if (!query.productId) query.productId = getRequestProductId(req);
    const { items, total } = await repo.list(query);
    return { items, total, limit: query.limit, offset: query.offset };
  });

  // Get item
  app.get('/items/:id', async req => {
    await extractAuth(req);
    const { id } = req.params as { id: string };
    const item = await repo.getById(id);
    if (!item) throw new NotFoundError('Item not found');
    return item;
  });

  // Create item
  app.post('/items', async (req, reply) => {
    const auth = await extractAuth(req);
    const parsed = CreateItemSchema.safeParse(req.body);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }
    const input = parsed.data;
    const pid = input.productId || getRequestProductId(req);
    const now = new Date().toISOString();

    const doc: TrackerItemDoc = {
      id: `trk_${crypto.randomUUID()}`,
      productId: pid,
      type: input.type,
      status: 'open',
      priority: input.priority,
      title: input.title,
      description: input.description,
      labels: input.labels,
      assignee: input.assignee,
      reportedBy: auth.sub,
      source: input.source,
      visibility: input.visibility,
      voteCount: 0,
      commentCount: 0,
      priorityOrder: PRIORITY_ORDER[input.priority] ?? 2,
      targetRelease: input.targetRelease,
      createdAt: now,
      updatedAt: now,
    };

    const created = await repo.create(doc);
    reply.code(201);
    return created;
  });

  // Update item
  app.put('/items/:id', async req => {
    await extractAuth(req);
    const { id } = req.params as { id: string };
    const existing = await repo.getById(id);
    if (!existing) throw new NotFoundError('Item not found');

    const parsed = UpdateItemSchema.safeParse(req.body);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }
    const updates: Partial<TrackerItemDoc> = { ...parsed.data };
    if (parsed.data.priority) {
      updates.priorityOrder = PRIORITY_ORDER[parsed.data.priority] ?? 2;
    }
    const updated = await repo.update(id, updates);
    if (!updated) throw new NotFoundError('Item update failed');
    return updated;
  });

  // Quick status transition
  app.patch('/items/:id/status', async req => {
    await extractAuth(req);
    const { id } = req.params as { id: string };
    const existing = await repo.getById(id);
    if (!existing) throw new NotFoundError('Item not found');

    const parsed = UpdateStatusSchema.safeParse(req.body);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }
    const updated = await repo.update(id, { status: parsed.data.status });
    if (!updated) throw new NotFoundError('Status update failed');
    return updated;
  });

  // Delete item
  app.delete('/items/:id', async req => {
    await extractAuth(req);
    const { id } = req.params as { id: string };
    const existing = await repo.getById(id);
    if (!existing) throw new NotFoundError('Item not found');
    await repo.remove(id);
    return { success: true };
  });
}
