/**
 * Kubernetes Adapter Tests
 */

import { describe, it, expect, beforeEach, vi } from 'vitest'
import { KubernetesAdapter } from '../kubernetes/adapter'
import * as k8s from '@kubernetes/client-node'

// Mock Kubernetes client
vi.mock('@kubernetes/client-node', () => ({
  KubeConfig: vi.fn().mockImplementation(() => ({
    loadFromDefault: vi.fn(),
    loadFromFile: vi.fn(),
    loadFromString: vi.fn(),
    setCurrentContext: vi.fn(),
    makeApiClient: vi.fn(),
  })),
  CoreV1Api: vi.fn(),
  AppsV1Api: vi.fn(),
  MetricsV1beta1Api: vi.fn(),
}))

describe('KubernetesAdapter', () => {
  let adapter: KubernetesAdapter
  let mockK8sApi: any
  let mockK8sAppsApi: any

  beforeEach(() => {
    mockK8sApi = {
      listPodForAllNamespaces: vi.fn(),
      listServiceForAllNamespaces: vi.fn(),
      readNamespacedPod: vi.fn(),
      readNamespacedService: vi.fn(),
      deleteNamespacedPod: vi.fn(),
      getCode: vi.fn().mockResolvedValue(200),
    }

    mockK8sAppsApi = {
      listDeploymentForAllNamespaces: vi.fn(),
      readNamespacedDeployment: vi.fn(),
      createNamespacedDeployment: vi.fn(),
      replaceNamespacedDeployment: vi.fn(),
      deleteNamespacedDeployment: vi.fn(),
    }

    const mockKc = {
      loadFromDefault: vi.fn(),
      setCurrentContext: vi.fn(),
      makeApiClient: vi.fn((api: any) => {
        if (api === k8s.CoreV1Api) return mockK8sApi
        if (api === k8s.AppsV1Api) return mockK8sAppsApi
        return mockK8sApi
      }),
    }

    vi.mocked(k8s.KubeConfig).mockImplementation(() => mockKc as any)

    adapter = new KubernetesAdapter({
      prometheusUrl: 'http://localhost:9090',
    })
  })

  describe('discoverResources', () => {
    it('should discover pods, services, and deployments', async () => {
      mockK8sApi.listPodForAllNamespaces.mockResolvedValue({
        body: {
          items: [
            {
              metadata: {
                name: 'test-pod',
                namespace: 'default',
                uid: 'pod-uid-1',
                labels: { app: 'test' },
                creationTimestamp: new Date().toISOString(),
              },
              spec: {
                nodeName: 'node-1',
                containers: [{ name: 'container-1', image: 'nginx:latest' }],
              },
              status: { phase: 'Running' },
            },
          ],
        },
      })

      mockK8sApi.listServiceForAllNamespaces.mockResolvedValue({
        body: {
          items: [
            {
              metadata: {
                name: 'test-service',
                namespace: 'default',
                labels: { app: 'test' },
                creationTimestamp: new Date().toISOString(),
              },
              spec: {
                type: 'ClusterIP',
                ports: [{ port: 80, protocol: 'TCP' }],
              },
            },
          ],
        },
      })

      mockK8sAppsApi.listDeploymentForAllNamespaces.mockResolvedValue({
        body: {
          items: [
            {
              metadata: {
                name: 'test-deployment',
                namespace: 'default',
                labels: { app: 'test' },
                creationTimestamp: new Date().toISOString(),
              },
              spec: { replicas: 3 },
              status: { replicas: 3, readyReplicas: 3 },
            },
          ],
        },
      })

      const resources = await adapter.discoverResources()

      expect(resources.length).toBe(3)
      expect(resources.some((r) => r.type === 'pod')).toBe(true)
      expect(resources.some((r) => r.type === 'service')).toBe(true)
      expect(resources.some((r) => r.type === 'deployment')).toBe(true)
    })
  })

  describe('getMetrics', () => {
    it('should fetch metrics from Prometheus', async () => {
      global.fetch = vi.fn().mockResolvedValue({
        ok: true,
        json: async () => ({
          status: 'success',
          data: {
            result: [
              {
                values: [
                  [Math.floor(Date.now() / 1000), '0.5'],
                  [Math.floor(Date.now() / 1000) + 15, '0.6'],
                ],
              },
            ],
          },
        }),
      })

      const metrics = await adapter.getMetrics('default/test-pod', {
        start: new Date(Date.now() - 3600000),
        end: new Date(),
      })

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

  describe('getRelationships', () => {
    it('should discover pod to service relationships', async () => {
      mockK8sApi.listNamespacedService.mockResolvedValue({
        body: {
          items: [
            {
              metadata: { name: 'test-service', namespace: 'default' },
              spec: {
                selector: { app: 'test' },
                ports: [{ port: 80 }],
              },
            },
          ],
        },
      })

      mockK8sApi.readNamespacedPod.mockResolvedValue({
        body: {
          metadata: {
            name: 'test-pod',
            namespace: 'default',
            labels: { app: 'test' },
          },
        },
      })

      const relationships = await adapter.getRelationships('default/test-pod')

      expect(relationships.length).toBeGreaterThan(0)
      expect(relationships.some((r) => r.type === 'exposed_by')).toBe(true)
    })
  })
})

