/**
 * Factory for creating a Fastify service app with standard middleware.
 *
 * Includes: CORS, x-request-id propagation, health endpoint, ServiceError handler.
 */

import { randomUUID } from 'node:crypto';
import Fastify from 'fastify';
import cors from '@fastify/cors';
import { ServiceError } from '@bytelyst/errors';
import type { ServiceAppOptions, FastifyApp } from './types.js';

/**
 * Create a Fastify app preconfigured with common middleware.
 *
 * @example
 * ```ts
 * const app = await createServiceApp({
 *   name: "platform-service",
 *   version: "0.1.0",
 *   description: "Auth, audit, flags, notifications",
 *   corsOrigin: process.env.CORS_ORIGIN,
 * });
 * await app.register(authRoutes, { prefix: "/api" });
 * await startService(app, { port: 4003 });
 * ```
 */
export async function createServiceApp(options: ServiceAppOptions): Promise<FastifyApp> {
  const {
    name,
    version,
    description,
    corsOrigin,
    logger = true,
    logLevel,
    swagger,
    metrics,
  } = options;

  const app = Fastify({
    logger: logger ? (logLevel ? { level: logLevel } : true) : false,
  });

  // CORS — deny all origins when CORS_ORIGIN is not explicitly set
  const origin = corsOrigin ? corsOrigin.split(',').map(o => o.trim()) : false;
  await app.register(cors, { origin });

  // OpenAPI spec (optional — consumer must have @fastify/swagger installed)
  if (swagger) {
    const swaggerPlugin = (await import('@fastify/swagger')).default;
    await app.register(swaggerPlugin, {
      openapi: {
        info: {
          title: swagger.title,
          version,
          ...(swagger.description && { description: swagger.description }),
        },
        ...(swagger.port && { servers: [{ url: `http://localhost:${swagger.port}` }] }),
      },
    });

    // Swagger UI — serves interactive API docs at /documentation
    try {
      const swaggerUiPlugin = (await import('@fastify/swagger-ui')).default;
      await app.register(swaggerUiPlugin, {
        routePrefix: '/documentation',
        uiConfig: { docExpansion: 'list', deepLinking: true },
      });
    } catch {
      // @fastify/swagger-ui not installed — skip silently
    }
  }

  // Prometheus metrics (optional — consumer must have fastify-metrics installed)
  if (metrics) {
    const metricsMod = await import('fastify-metrics');
    const plugin = metricsMod.default as unknown as Parameters<typeof app.register>[0];
    await app.register(plugin, { endpoint: '/metrics' });
  }

  // x-request-id propagation
  app.addHook('onRequest', async (req, reply) => {
    const requestId = (req.headers['x-request-id'] as string) || randomUUID();
    req.headers['x-request-id'] = requestId;
    reply.header('x-request-id', requestId);
    req.log = req.log.child({ requestId });
  });

  // Health check
  app.get('/health', async req => ({
    status: 'ok',
    service: name,
    version,
    ...(description && { description }),
    timestamp: new Date().toISOString(),
    requestId: req.headers['x-request-id'],
  }));

  // ServiceError-aware error handler
  app.setErrorHandler((error, _req, reply) => {
    if (error instanceof ServiceError) {
      const body: Record<string, unknown> = { error: error.message };
      if (error.details) body.details = error.details;
      reply.code(error.statusCode).send(body);
      return;
    }
    app.log.error(error);
    reply.code(500).send({ error: 'Internal server error' });
  });

  return app;
}
