/**
 * Cloudflare Adapter Tests
 */

import { describe, it, expect, beforeEach, vi } from 'vitest'
import { CloudflareAdapter } from '../cloudflare/adapter'

// Mock fetch globally
global.fetch = vi.fn()

describe('CloudflareAdapter', () => {
  let adapter: CloudflareAdapter

  beforeEach(() => {
    adapter = new CloudflareAdapter({
      apiToken: 'test-token',
      accountId: 'test-account-id',
    })
    vi.clearAllMocks()
  })

  describe('discoverResources', () => {
    it('should discover tunnels and zones', async () => {
      const mockTunnels = {
        success: true,
        result: [
          {
            id: 'tunnel-1',
            name: 'test-tunnel',
            status: 'active',
            connections: 5,
            created_at: new Date().toISOString(),
          },
        ],
      }

      const mockZones = {
        success: true,
        result: [
          {
            id: 'zone-1',
            name: 'example.com',
            status: 'active',
            account: { id: 'test-account-id' },
            name_servers: ['ns1.example.com'],
            plan: { name: 'Pro' },
            created_on: new Date().toISOString(),
            modified_on: new Date().toISOString(),
          },
        ],
      }

      ;(global.fetch as any)
        .mockResolvedValueOnce({
          ok: true,
          json: async () => mockTunnels,
        })
        .mockResolvedValueOnce({
          ok: true,
          json: async () => mockZones,
        })

      const resources = await adapter.discoverResources()

      expect(resources).toHaveLength(2)
      expect(resources[0].type).toBe('tunnel')
      expect(resources[1].type).toBe('dns_zone')
    })

    it('should handle API errors gracefully', async () => {
      ;(global.fetch as any).mockResolvedValue({
        ok: false,
        status: 401,
        statusText: 'Unauthorized',
      })

      await expect(adapter.discoverResources()).rejects.toThrow()
    })
  })

  describe('createResource', () => {
    it('should create a tunnel', async () => {
      const mockTunnel = {
        success: true,
        result: {
          id: 'tunnel-1',
          name: 'new-tunnel',
          status: 'active',
          created_at: new Date().toISOString(),
        },
      }

      ;(global.fetch as any).mockResolvedValue({
        ok: true,
        json: async () => mockTunnel,
      })

      const resource = await adapter.createResource({
        name: 'new-tunnel',
        type: 'tunnel',
        config: { config_src: 'local' },
      })

      expect(resource).toBeDefined()
      expect(resource.name).toBe('new-tunnel')
      expect(global.fetch).toHaveBeenCalledWith(
        expect.stringContaining('/cfd_tunnel'),
        expect.objectContaining({
          method: 'POST',
        })
      )
    })

    it('should create a DNS zone', async () => {
      const mockZone = {
        success: true,
        result: {
          id: 'zone-1',
          name: 'example.com',
          status: 'active',
          account: { id: 'test-account-id' },
          created_on: new Date().toISOString(),
          modified_on: new Date().toISOString(),
        },
      }

      ;(global.fetch as any).mockResolvedValue({
        ok: true,
        json: async () => mockZone,
      })

      const resource = await adapter.createResource({
        name: 'example.com',
        type: 'dns_zone',
        config: {},
      })

      expect(resource).toBeDefined()
      expect(resource.name).toBe('example.com')
    })
  })

  describe('getMetrics', () => {
    it('should fetch metrics for a zone', async () => {
      const mockAnalytics = {
        success: true,
        result: {
          totals: {
            requests: { all: 1000, cached: 800 },
            bandwidth: { all: 5000000 },
          },
        },
      }

      ;(global.fetch as any).mockResolvedValue({
        ok: true,
        json: async () => mockAnalytics,
      })

      const metrics = await adapter.getMetrics('zone-1', {
        start: new Date(Date.now() - 3600000),
        end: new Date(),
      })

      expect(metrics.length).toBeGreaterThan(0)
      expect(metrics.some((m) => m.metricType === 'REQUEST_RATE')).toBe(true)
    })
  })

  describe('getRelationships', () => {
    it('should discover tunnel to zone relationships', async () => {
      const mockTunnel = {
        success: true,
        result: {
          id: 'tunnel-1',
          name: 'test-tunnel',
        },
      }

      const mockRoutes = {
        success: true,
        result: [
          {
            zone_id: 'zone-1',
            hostname: 'example.com',
            path: '/',
          },
        ],
      }

      ;(global.fetch as any)
        .mockResolvedValueOnce({
          ok: true,
          json: async () => mockTunnel,
        })
        .mockResolvedValueOnce({
          ok: true,
          json: async () => mockRoutes,
        })

      const relationships = await adapter.getRelationships('tunnel-1')

      expect(relationships.length).toBeGreaterThan(0)
      expect(relationships[0].type).toBe('routes_to')
    })
  })

  describe('healthCheck', () => {
    it('should return healthy when API is accessible', async () => {
      ;(global.fetch as any).mockResolvedValue({
        ok: true,
      })

      const health = await adapter.healthCheck()

      expect(health.status).toBe('healthy')
    })

    it('should return unhealthy when API is inaccessible', async () => {
      ;(global.fetch as any).mockResolvedValue({
        ok: false,
        status: 401,
      })

      const health = await adapter.healthCheck()

      expect(health.status).toBe('unhealthy')
    })
  })
})

