import type { FastifyInstance } from 'fastify';
import { BadRequestError, ForbiddenError, UnauthorizedError } 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 requireAdmin(req: import('fastify').FastifyRequest): string {
    const role = req.jwtPayload?.role;
    if (!role || !['super_admin', 'admin'].includes(role)) {
      throw new ForbiddenError('Admin access required');
    }
    const sub = req.jwtPayload?.sub;
    if (!sub) throw new UnauthorizedError('Missing sub in token');
    return sub;
  }

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

  // Update maintenance mode
  app.put('/settings/maintenance', async req => {
    const adminId = requireAdmin(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(DEFAULT_PRODUCT_ID, {
      ...parsed.data,
      updatedAt: new Date().toISOString(),
      updatedBy: adminId,
    });

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

    return config;
  });

  // Create a scheduled maintenance window
  app.post('/settings/maintenance/schedule', async (req, reply) => {
    const adminId = requireAdmin(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: DEFAULT_PRODUCT_ID,
      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: adminId,
      createdAt: new Date().toISOString(),
    });

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

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