import { FastifyInstance, FastifyRequest, FastifyReply } from 'fastify'
import { getDatabase } from '../lib/db'
import { HijackAlertsDatabaseClient } from '../features/hijack-alerts/db-client'
import { WebhookClient } from '../features/hijack-alerts/webhook-client'
import { checkForHijacks } from '../features/hijack-alerts/detector'
import crypto from 'crypto'

const db = new HijackAlertsDatabaseClient(getDatabase())
const webhookClient = new WebhookClient()

function generateSecretKey(): string {
  return 'sk_' + crypto.randomBytes(32).toString('hex')
}

interface RegisterWebhookRequest {
  endpoint_url: string
  timeout_ms?: number
  max_retries?: number
}

interface CreateHijackRequest {
  asn: number
  prefix: string
}

export async function hijackAlertsRoutes(fastify: FastifyInstance): Promise<void> {
  // Register webhook subscription
  fastify.post<{ Querystring: { asn: string } }>(
    '/webhooks',
    async (request: FastifyRequest<{ Querystring: { asn: string }; Body: RegisterWebhookRequest }>, reply: FastifyReply) => {
      try {
        const asn = parseInt(request.query.asn, 10)
        const body = request.body as RegisterWebhookRequest

        if (isNaN(asn)) {
          return reply.status(400).send({ error: 'Invalid ASN' })
        }

        if (!body.endpoint_url) {
          return reply.status(400).send({ error: 'endpoint_url is required' })
        }

        const secretKey = generateSecretKey()
        const webhook = await db.createWebhookSubscription(
          {
            asn,
            endpoint_url: body.endpoint_url,
            timeout_ms: body.timeout_ms,
            max_retries: body.max_retries,
          },
          secretKey
        )

        return reply.status(201).send({
          id: webhook.id,
          asn: webhook.asn,
          endpoint_url: webhook.endpoint_url,
          secret_key: secretKey,
          created_at: webhook.created_at,
          active: webhook.active,
        })
      } catch (error) {
        console.error('[Routes] Error registering webhook:', error)
        return reply.status(500).send({ error: 'Failed to register webhook' })
      }
    }
  )

  // List webhooks for ASN
  fastify.get<{ Querystring: { asn: string } }>(
    '/webhooks',
    async (request: FastifyRequest<{ Querystring: { asn: string } }>, reply: FastifyReply) => {
      try {
        const asn = parseInt(request.query.asn, 10)

        if (isNaN(asn)) {
          return reply.status(400).send({ error: 'Invalid ASN' })
        }

        const webhooks = await db.getWebhooksByAsn(asn)

        return reply.send({
          asn,
          webhooks: webhooks.map((w) => ({
            id: w.id,
            endpoint_url: w.endpoint_url,
            active: w.active,
            failure_count: w.failure_count,
            last_triggered_at: w.last_triggered_at,
            max_retries: w.max_retries,
            timeout_ms: w.timeout_ms,
          })),
        })
      } catch (error) {
        console.error('[Routes] Error listing webhooks:', error)
        return reply.status(500).send({ error: 'Failed to list webhooks' })
      }
    }
  )

  // Delete webhook subscription
  fastify.delete<{ Params: { id: string } }>(
    '/webhooks/:id',
    async (request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply) => {
      try {
        const webhookId = parseInt(request.params.id, 10)

        if (isNaN(webhookId)) {
          return reply.status(400).send({ error: 'Invalid webhook ID' })
        }

        await db.deleteWebhookSubscription(webhookId)

        return reply.send({ deleted: true, id: webhookId })
      } catch (error) {
        console.error('[Routes] Error deleting webhook:', error)
        return reply.status(500).send({ error: 'Failed to delete webhook' })
      }
    }
  )

  // Test webhook delivery
  fastify.post<{ Params: { id: string } }>(
    '/webhooks/:id/test',
    async (request: FastifyRequest<{ Params: { id: string } }>, reply: FastifyReply) => {
      try {
        const webhookId = parseInt(request.params.id, 10)

        if (isNaN(webhookId)) {
          return reply.status(400).send({ error: 'Invalid webhook ID' })
        }

        const webhook = await db.getWebhookSubscription(webhookId)

        if (!webhook) {
          return reply.status(404).send({ error: 'Webhook not found' })
        }

        const testEvent = {
          id: 0,
          asn: webhook.asn,
          prefix: '0.0.0.0/0',
          detected_at: new Date(),
          expected_asn: webhook.asn,
          detected_asns: [webhook.asn],
          hijack_type: 'HIJACK' as const,
          severity: 'HIGH' as const,
          description: 'Test event from PeerCortex',
          details: { source: 'api-test', timestamp: new Date().toISOString() },
          resolved: false,
          resolved_at: null,
          created_at: new Date(),
        }

        const result = await webhookClient.sendWebhook(
          testEvent,
          webhook.endpoint_url,
          webhook.secret_key,
          webhook.timeout_ms
        )

        return reply.send({
          success: result.success,
          status: result.status,
          error: result.error ?? null,
          response_time_ms: result.response_time_ms,
        })
      } catch (error) {
        console.error('[Routes] Error testing webhook:', error)
        return reply.status(500).send({ error: 'Failed to test webhook' })
      }
    }
  )

  // List hijack events for ASN
  fastify.get<{ Querystring: { asn: string; limit?: string; offset?: string; resolved?: string } }>(
    '/hijacks',
    async (request: FastifyRequest<{ Querystring: { asn: string; limit?: string; offset?: string; resolved?: string } }>, reply: FastifyReply) => {
      try {
        const asn = parseInt(request.query.asn, 10)
        const limit = parseInt(request.query.limit ?? '50', 10)
        const offset = parseInt(request.query.offset ?? '0', 10)
        const resolved = request.query.resolved ? request.query.resolved === 'true' : undefined

        if (isNaN(asn)) {
          return reply.status(400).send({ error: 'Invalid ASN' })
        }

        const result = await db.getHijacksByAsn(asn, Math.min(limit, 500), offset, resolved)

        return reply.send({
          asn,
          total: result.total,
          limit,
          offset,
          events: result.events.map((e) => ({
            id: e.id,
            prefix: e.prefix,
            hijack_type: e.hijack_type,
            severity: e.severity,
            detected_at: e.detected_at,
            resolved: e.resolved,
            resolved_at: e.resolved_at,
            description: e.description,
          })),
        })
      } catch (error) {
        console.error('[Routes] Error listing hijacks:', error)
        return reply.status(500).send({ error: 'Failed to list hijacks' })
      }
    }
  )

  // Manually trigger hijack detection
  fastify.post<{ Body: CreateHijackRequest }>(
    '/hijacks/detect',
    async (request: FastifyRequest<{ Body: CreateHijackRequest }>, reply: FastifyReply) => {
      try {
        const body = request.body as CreateHijackRequest

        if (!body.asn || !body.prefix) {
          return reply.status(400).send({ error: 'asn and prefix are required' })
        }

        const results = await checkForHijacks(`${body.asn}:${body.prefix}`, db)

        if (results[0]?.detected && results[0]?.event) {
          const hijack = await db.insertHijackEvent(results[0].event)
          return reply.status(201).send({ detected: true, event: hijack })
        }

        return reply.send({ detected: false, reason: results[0]?.reason ?? 'No hijack detected' })
      } catch (error) {
        console.error('[Routes] Error detecting hijacks:', error)
        return reply.status(500).send({ error: 'Failed to detect hijacks' })
      }
    }
  )

  // Resolve hijack
  fastify.post<{ Params: { id: string }; Body: { resolution_notes: string } }>(
    '/hijacks/:id/resolve',
    async (request: FastifyRequest<{ Params: { id: string }; Body: { resolution_notes: string } }>, reply: FastifyReply) => {
      try {
        const eventId = parseInt(request.params.id, 10)

        if (isNaN(eventId)) {
          return reply.status(400).send({ error: 'Invalid event ID' })
        }

        const hijack = await db.resolveHijack(eventId, request.body.resolution_notes)

        return reply.send({
          id: hijack.id,
          resolved: hijack.resolved,
          resolved_at: hijack.resolved_at,
        })
      } catch (error) {
        console.error('[Routes] Error resolving hijack:', error)
        return reply.status(500).send({ error: 'Failed to resolve hijack' })
      }
    }
  )
}
