import type { FastifyInstance } from 'fastify';
import type { FastifySchema } from 'fastify';
import type pg from 'pg';
import { z } from 'zod';
import type { Authenticate } from '../../../shared/auth.js';
import { requireRole } from '../../../shared/auth.js';
import { parseJson } from '../../../shared/http-input.js';
import { errorSchema } from '../../../shared/swagger.js';
import { NotificationsService } from '../application/notifications-service.js';
import { PgNotificationsRepository } from '../infrastructure/pg-notifications-repository.js';

export interface NotificationsRoutesDeps {
  pool: pg.Pool;
  authenticate: Authenticate;
  emailProvider: import('../domain/ports.js').EmailProvider;
}

const dispatchSchema = z
  .object({
    eventId: z.string().min(1).max(120),
    template: z.enum(['order_confirmation', 'payment_failed', 'order_shipped', 'account_created']),
    recipient: z.string().email(),
    subject: z.string().min(1).max(200),
    body: z.string().min(1).max(5000),
  })
  .strip();

export async function registerNotificationsRoutes(
  app: FastifyInstance,
  deps: NotificationsRoutesDeps,
): Promise<void> {
  const service = new NotificationsService(
    new PgNotificationsRepository(deps.pool),
    deps.emailProvider,
  );

  const dispatchSwaggerSchema: FastifySchema = {
    tags: ['Admin'],
    summary: 'Dispatch notification (admin)',
    body: { type: 'object' },
    response: { 401: errorSchema, 403: errorSchema },
  };
  app.post('/notifications/dispatch', { schema: dispatchSwaggerSchema }, async (request, reply) => {
    const user = await deps.authenticate(request);
    requireRole(user, 'admin');
    const input = parseJson(dispatchSchema, request.body);
    const outcome = await service.dispatch(input);
    return reply.send({ outcome });
  });

  const getMessageSchema: FastifySchema = {
    tags: ['Admin'],
    summary: 'Get notification message (admin)',
    params: { type: 'object', required: ['eventId'], properties: { eventId: { type: 'string' } } },
    response: { 401: errorSchema, 403: errorSchema, 404: errorSchema },
  };
  app.get(
    '/notifications/messages/:eventId',
    { schema: getMessageSchema },
    async (request, reply) => {
      const user = await deps.authenticate(request);
      requireRole(user, 'admin');
      const params = z.object({ eventId: z.string().min(1).max(120) }).parse(request.params);
      const repo = new PgNotificationsRepository(deps.pool);
      const found = await repo.findByEventId(params.eventId);
      if (!found)
        throw new (await import('../../../shared/errors.js')).AppError(
          404,
          'NOT_FOUND',
          'Message not found',
        );
      return reply.send(found);
    },
  );
}
