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

export async function ipRuleRoutes(app: FastifyInstance) {
  function requireIpRulesRead(req: import('fastify').FastifyRequest) {
    return requireJwtOrApiKey(req, {
      jwtRoles: ['super_admin', 'admin'],
      apiKeyScopes: ['ip-rules:read'],
      apiKeyTokenTypes: ['service_api'],
      rateLimitKey: 'ip-rules:read',
    });
  }

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

  // List all IP rules
  app.get('/ratelimit/ip-rules', async req => {
    const access = await requireIpRulesRead(req);
    return repo.listRules(access.productId);
  });

  // Create an IP rule
  app.post('/ratelimit/ip-rules', async (req, reply) => {
    const access = await requireIpRulesWrite(req);
    const parsed = CreateIPRuleSchema.safeParse(req.body);
    if (!parsed.success) {
      throw new BadRequestError(parsed.error.issues.map(i => i.message).join('; '));
    }

    const doc: IPRuleDoc = {
      id: `ipr_${crypto.randomUUID()}`,
      productId: access.productId,
      ip: parsed.data.ip,
      action: parsed.data.action,
      reason: parsed.data.reason,
      createdBy: access.actorId,
      createdAt: new Date().toISOString(),
      expiresAt: parsed.data.expiresAt,
    };

    const created = await repo.createRule(doc);
    req.log.info(
      { ruleId: created.id, ip: created.ip, action: created.action },
      `[ip-rules] IP rule created: ${created.action} ${created.ip}`
    );

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

  // Delete an IP rule
  app.delete('/ratelimit/ip-rules/:id', async req => {
    const access = await requireIpRulesWrite(req);
    const { id } = req.params as { id: string };
    const deleted = await repo.deleteRule(id, access.productId);
    if (!deleted) throw new BadRequestError('IP rule not found');
    return { success: true };
  });

  // Check if an IP is allowed/denied (utility endpoint)
  app.get('/ratelimit/check-ip/:ip', async req => {
    const access = await requireIpRulesRead(req);
    const { ip } = req.params as { ip: string };
    const result = await repo.checkIP(ip, access.productId);
    return { ip, action: result, hasRule: result !== null };
  });
}
