import type { FastifyInstance } from 'fastify';
import { getDeploymentsByService, getRecentDeployments, getDeploymentById } from './repository.js';
import { triggerDeployment } from './orchestrator.js';
import { getServiceById } from '../services/repository.js';
import { requireAdmin, BadRequestError } from '../../lib/auth.js';
import {
  DeploymentParamsSchema,
  TriggerDeploymentParamsSchema,
  QueryParamsSchema,
} from './types.js';
import { getContainer } from '../../lib/cosmos-init.js';
import { createAuditLog } from '../audit/repository.js';
import { productId } from '../../lib/config.js';

export async function deploymentRoutes(fastify: FastifyInstance) {
  // Get recent deployments across all services (admin only)
  fastify.get('/deployments', {
    preHandler: async (req) => requireAdmin(req),
  }, async (req, reply) => {
    const query = QueryParamsSchema.parse(req.query);
    const deployments = await getRecentDeployments(query.limit);
    return reply.send(deployments);
  });

  // Get deployments for a specific service (admin only)
  fastify.get('/deployments/service/:serviceId', {
    preHandler: async (req) => requireAdmin(req),
  }, async (req, reply) => {
    const params = TriggerDeploymentParamsSchema.parse(req.params);
    const query = QueryParamsSchema.parse(req.query);
    const deployments = await getDeploymentsByService(params.serviceId, query.limit);
    return reply.send(deployments);
  });

  // Get single deployment (admin only)
  fastify.get('/deployments/:id', {
    preHandler: async (req) => requireAdmin(req),
  }, async (req, reply) => {
    const params = DeploymentParamsSchema.parse(req.params);
    const deployment = await getDeploymentById(params.id);
    if (!deployment) {
      return reply.code(404).send({ error: 'Deployment not found' });
    }
    return reply.send(deployment);
  });

  // Get deployment logs (admin only). Returns the captured stdout/stderr +
  // current status as a single JSON payload. The web client polls this for
  // running deployments — there is intentionally no SSE/streaming variant
  // (see server.ts for the full rationale).
  fastify.get('/deployments/:id/logs', {
    preHandler: async (req) => requireAdmin(req),
  }, async (req, reply) => {
    const params = DeploymentParamsSchema.parse(req.params);
    const deployment = await getDeploymentById(params.id);

    if (!deployment) {
      return reply.code(404).send({ error: 'Deployment not found' });
    }

    // Return logs as JSON
    return reply.send({
      logs: deployment.logs,
      status: deployment.status,
    });
  });

  // Trigger deployment (admin only)
  fastify.post('/deployments/trigger/:serviceId', {
    preHandler: async (req) => requireAdmin(req),
  }, async (req, reply) => {
    try {
      const params = TriggerDeploymentParamsSchema.parse(req.params);
      const { userId } = requireAdmin(req);

      const service = await getServiceById(params.serviceId);
      if (!service) {
        return reply.code(404).send({ error: 'Service not found' });
      }

      const deploymentId = await triggerDeployment(service, userId);

      await createAuditLog({
        action: 'trigger',
        entityType: 'deployment',
        entityId: deploymentId,
        userId: (req as any).authUserId || 'unknown',
        role: (req as any).authRole || 'unknown',
        productId,
        details: { serviceId: params.serviceId, serviceName: service.name },
      });

      return reply.send({ deploymentId, status: 'triggered' });
    } catch (error) {
      if (error instanceof Error) {
        throw new BadRequestError(error.message);
      }
      throw error;
    }
  });
}
