import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest'
import nock from 'nock'
import { HijackAlertsDatabaseClient } from '../db-client'
import { WebhookClient } from '../webhook-client'
import { RetryScheduler } from '../retry-scheduler'

describe('Hijack Alerts Integration', () => {
  let mockDbClient: Partial<HijackAlertsDatabaseClient>
  let webhookClient: WebhookClient

  beforeEach(() => {
    webhookClient = new WebhookClient()
    mockDbClient = {
      getFailedDeliveriesForRetry: vi.fn().mockResolvedValue([]),
      recordWebhookDelivery: vi.fn().mockResolvedValue({
        id: 1,
        subscription_id: 1,
        event_id: 1,
        attempt_number: 1,
        sent_at: new Date(),
        response_status: 200,
        response_body: null,
        error_message: null,
        next_retry_at: null,
      }),
      updateWebhookStatus: vi.fn().mockResolvedValue(null),
      updateWebhookLastTriggered: vi.fn().mockResolvedValue(undefined),
    }
    nock.cleanAll()
  })

  afterEach(() => {
    nock.cleanAll()
  })

  describe('End-to-end webhook delivery', () => {
    it('should send webhook and record delivery', async () => {
      const event = {
        id: 1,
        asn: 13335,
        prefix: '185.1.0.0/24',
        detected_at: new Date(),
        expected_asn: 13335,
        detected_asns: [12345],
        hijack_type: 'HIJACK' as const,
        severity: 'HIGH' as const,
        description: 'BGP hijack detected',
        details: { source: 'test' },
        resolved: false,
        resolved_at: null,
        created_at: new Date(),
      }

      nock('https://webhook.example.com')
        .post('/notify')
        .reply(200)

      const result = await webhookClient.sendWebhook(event, 'https://webhook.example.com/notify', 'secret_key', 5000)

      expect(result.success).toBe(true)
    })

    it('should handle retry scheduler with failed deliveries', async () => {
      const failedDeliveries = [
        {
          webhook: {
            id: 1,
            asn: 13335,
            endpoint_url: 'https://webhook.example.com/notify',
            secret_key: 'secret_key',
            created_at: new Date(),
            last_triggered_at: null,
            failure_count: 0,
            active: true,
            max_retries: 3,
            timeout_ms: 5000,
            metadata: {},
          },
          event: {
            id: 1,
            asn: 13335,
            prefix: '185.1.0.0/24',
            detected_at: new Date(),
            expected_asn: 13335,
            detected_asns: [12345],
            hijack_type: 'HIJACK' as const,
            severity: 'HIGH' as const,
            description: 'BGP hijack',
            details: {},
            resolved: false,
            resolved_at: null,
            created_at: new Date(),
          },
          delivery: {
            id: 1,
            subscription_id: 1,
            event_id: 1,
            attempt_number: 1,
            sent_at: new Date(),
            response_status: null,
            response_body: null,
            error_message: 'Timeout',
            next_retry_at: new Date(),
          },
        },
      ]

      ;(mockDbClient.getFailedDeliveriesForRetry as any).mockResolvedValue(failedDeliveries)

      nock('https://webhook.example.com')
        .post('/notify')
        .reply(200)

      const scheduler = new RetryScheduler(mockDbClient as HijackAlertsDatabaseClient, webhookClient)

      // Note: This tests the scheduler logic directly, not the cron scheduling
      await (scheduler as any).processFailedDeliveries()

      expect(mockDbClient.recordWebhookDelivery).toHaveBeenCalled()
    })
  })

  describe('Webhook signature validation', () => {
    it('should generate consistent signatures', () => {
      const payload = JSON.stringify({ test: 'data' })
      const secret = 'test_secret'

      const sig1 = (webhookClient as any).generateSignature(payload, secret)
      const sig2 = (webhookClient as any).generateSignature(payload, secret)

      expect(sig1).toBe(sig2)
    })

    it('should generate different signatures for different secrets', () => {
      const payload = JSON.stringify({ test: 'data' })

      const sig1 = (webhookClient as any).generateSignature(payload, 'secret1')
      const sig2 = (webhookClient as any).generateSignature(payload, 'secret2')

      expect(sig1).not.toBe(sig2)
    })
  })

  describe('Error handling', () => {
    it('should handle network errors gracefully', async () => {
      nock('https://webhook.example.com')
        .post('/notify')
        .replyWithError('Network error')

      const event = {
        id: 1,
        asn: 13335,
        prefix: '185.1.0.0/24',
        detected_at: new Date(),
        expected_asn: 13335,
        detected_asns: [12345],
        hijack_type: 'HIJACK' as const,
        severity: 'HIGH' as const,
        description: 'BGP hijack',
        details: {},
        resolved: false,
        resolved_at: null,
        created_at: new Date(),
      }

      const result = await webhookClient.sendWebhook(event, 'https://webhook.example.com/notify', 'secret', 5000)

      expect(result.success).toBe(false)
      expect(result.error).toBeDefined()
    })

    it('should track response times', async () => {
      nock('https://webhook.example.com')
        .post('/notify')
        .reply(200)

      const event = {
        id: 1,
        asn: 13335,
        prefix: '185.1.0.0/24',
        detected_at: new Date(),
        expected_asn: 13335,
        detected_asns: [12345],
        hijack_type: 'HIJACK' as const,
        severity: 'HIGH' as const,
        description: 'BGP hijack',
        details: {},
        resolved: false,
        resolved_at: null,
        created_at: new Date(),
      }

      const result = await webhookClient.sendWebhook(event, 'https://webhook.example.com/notify', 'secret', 5000)

      expect(result.response_time_ms).toBeGreaterThanOrEqual(0)
    })
  })
})
