import type { FastifyInstance } from 'fastify';
import { requireJwtOrApiKey } from '../../lib/api-key-auth.js';
import { BadRequestError } from '../../lib/errors.js';
import { UpdateMaintenanceSchema, CreateMaintenanceWindowSchema } from './types.js';
import * as repo from './repository.js';

const DEFAULT_PRODUCT_ID = 'lysnrai';

export async function maintenanceRoutes(app: FastifyInstance) {
  // ── Public endpoints ───────────────────────────────────────

  // Check current maintenance mode (clients poll this)
  app.get('/settings/maintenance', async () => {
    const config = await repo.getMaintenanceConfig(DEFAULT_PRODUCT_ID);
    return {
      mode: config.mode,
      message: config.message,
      affectedServices: config.affectedServices,
      scheduledStart: config.scheduledStart,
      scheduledEnd: config.scheduledEnd,
    };
  });

  // List upcoming maintenance windows
  app.get('/settings/maintenance/schedule', async () => {
    return repo.listUpcomingWindows(DEFAULT_PRODUCT_ID);
  });

  // ── Admin endpoints ────────────────────────────────────────

  function requireMaintenanceRead(req: import('fastify').FastifyRequest) {
    return requireJwtOrApiKey(req, {
      jwtRoles: ['super_admin', 'admin'],
      apiKeyScopes: ['maintenance:read'],
      apiKeyTokenTypes: ['service_api'],
      rateLimitKey: 'maintenance:read',
    });
  }

  function requireMaintenanceWrite(req: import('fastify').FastifyRequest) {
    return requireJwtOrApiKey(req, {
      jwtRoles: ['super_admin', 'admin'],
      apiKeyScopes: ['maintenance:write'],
      apiKeyTokenTypes: ['service_api'],
      rateLimitKey: 'maintenance:write',
    });
  }

  // Get full maintenance config (admin sees bypass rules too)
  app.get('/settings/maintenance/full', async req => {
    const access = await requireMaintenanceRead(req);
    return repo.getMaintenanceConfig(access.productId);
  });

  // Update maintenance mode
  app.put('/settings/maintenance', async req => {
    const access = await requireMaintenanceWrite(req);
    const parsed = UpdateMaintenanceSchema.safeParse(req.body);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }

    const config = await repo.updateMaintenanceConfig(access.productId, {
      ...parsed.data,
      updatedAt: new Date().toISOString(),
      updatedBy: access.actorId,
    });

    req.log.info(
      { mode: config.mode, adminId: access.actorId },
      `[maintenance] Mode changed to '${config.mode}'`
    );

    return config;
  });

  // Create a scheduled maintenance window
  app.post('/settings/maintenance/schedule', async (req, reply) => {
    const access = await requireMaintenanceWrite(req);
    const parsed = CreateMaintenanceWindowSchema.safeParse(req.body);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }

    if (new Date(parsed.data.scheduledEnd) <= new Date(parsed.data.scheduledStart)) {
      throw new BadRequestError('scheduledEnd must be after scheduledStart');
    }

    const window = await repo.createWindow({
      id: `mw_${crypto.randomUUID()}`,
      productId: access.productId,
      title: parsed.data.title,
      message: parsed.data.message,
      mode: parsed.data.mode,
      scheduledStart: parsed.data.scheduledStart,
      scheduledEnd: parsed.data.scheduledEnd,
      affectedServices: parsed.data.affectedServices,
      createdBy: access.actorId,
      createdAt: new Date().toISOString(),
    });

    return reply.status(201).send(window);
  });

  // Delete a scheduled maintenance window
  app.delete('/settings/maintenance/schedule/:id', async req => {
    const access = await requireMaintenanceWrite(req);
    const { id } = req.params as { id: string };
    const deleted = await repo.deleteWindow(id, access.productId);
    if (!deleted) throw new BadRequestError('Maintenance window not found');
    return { success: true };
  });
}
