import { Context } from '../types/context'
import { logger } from '../lib/logger'
import * as k8s from '@kubernetes/client-node'

export interface InferenceEndpoint {
  id: string
  name: string
  modelId: string
  status: string
  createdAt: Date
  namespace?: string
  endpoint?: string
}

/**
 * Creates a Kubernetes deployment for an inference endpoint
 */
export async function createInferenceEndpoint(
  context: Context,
  input: {
    name: string
    modelId: string
    image?: string
    namespace?: string
    replicas?: number
    resources?: {
      cpu?: string
      memory?: string
      gpu?: number
    }
    port?: number
  }
): Promise<InferenceEndpoint> {
  try {
    const kc = new k8s.KubeConfig()
    kc.loadFromDefault()
    const k8sAppsApi = kc.makeApiClient(k8s.AppsV1Api)
    const k8sCoreApi = kc.makeApiClient(k8s.CoreV1Api)

    const namespace = input.namespace || 'inference'
    const name = `inference-${input.name.toLowerCase().replace(/[^a-z0-9-]/g, '-')}`
    const image = input.image || `model-registry/${input.modelId}:latest`
    const replicas = input.replicas || 1
    const port = input.port || 8080

    // Ensure namespace exists
    try {
      await k8sCoreApi.readNamespace(namespace)
    } catch (error) {
      // Namespace doesn't exist, create it
      const ns: k8s.V1Namespace = {
        apiVersion: 'v1',
        kind: 'Namespace',
        metadata: {
          name: namespace,
          labels: {
            'app.kubernetes.io/name': 'inference',
          },
        },
      }
      await k8sCoreApi.createNamespace(ns)
    }

    // Create deployment
    const deployment: k8s.V1Deployment = {
      apiVersion: 'apps/v1',
      kind: 'Deployment',
      metadata: {
        name,
        namespace,
        labels: {
          'app': name,
          'model-id': input.modelId,
          'component': 'inference',
        },
      },
      spec: {
        replicas,
        selector: {
          matchLabels: {
            app: name,
          },
        },
        template: {
          metadata: {
            labels: {
              app: name,
              'model-id': input.modelId,
            },
          },
          spec: {
            containers: [
              {
                name: 'inference',
                image,
                ports: [
                  {
                    containerPort: port,
                    name: 'http',
                  },
                ],
                env: [
                  {
                    name: 'MODEL_ID',
                    value: input.modelId,
                  },
                  {
                    name: 'PORT',
                    value: port.toString(),
                  },
                ],
                resources: {
                  requests: {
                    cpu: input.resources?.cpu || '500m',
                    memory: input.resources?.memory || '1Gi',
                  },
                  limits: {
                    cpu: input.resources?.cpu ? `${parseFloat(input.resources.cpu) * 2}${input.resources.cpu.slice(-1)}` : '2000m',
                    memory: input.resources?.memory ? `${parseFloat(input.resources.memory) * 2}${input.resources.memory.slice(-2)}` : '2Gi',
                  },
                },
                livenessProbe: {
                  httpGet: {
                    path: '/health',
                    port: port,
                  },
                  initialDelaySeconds: 30,
                  periodSeconds: 10,
                },
                readinessProbe: {
                  httpGet: {
                    path: '/ready',
                    port: port,
                  },
                  initialDelaySeconds: 10,
                  periodSeconds: 5,
                },
              },
            ],
          },
        },
      },
    }

    // Add GPU support if specified
    if (input.resources?.gpu && input.resources.gpu > 0) {
      deployment.spec!.template!.spec!.containers![0].resources!.limits!['nvidia.com/gpu'] = input.resources.gpu.toString()
    }

    const deploymentResult = await k8sAppsApi.createNamespacedDeployment(namespace, deployment)

    // Create service
    const service: k8s.V1Service = {
      apiVersion: 'v1',
      kind: 'Service',
      metadata: {
        name,
        namespace,
        labels: {
          app: name,
        },
      },
      spec: {
        selector: {
          app: name,
        },
        ports: [
          {
            port: 80,
            targetPort: port,
            name: 'http',
          },
        ],
        type: 'ClusterIP',
      },
    }

    await k8sCoreApi.createNamespacedService(namespace, service)

    const endpointId = `${namespace}/${name}`
    const endpoint = `${name}.${namespace}.svc.cluster.local:80`

    return {
      id: endpointId,
      name: input.name,
      modelId: input.modelId,
      status: 'PROVISIONING',
      createdAt: new Date(),
      namespace,
      endpoint,
    }
  } catch (error) {
    logger.error('Error creating inference endpoint', { error })
    throw new Error(`Failed to create inference endpoint: ${error instanceof Error ? error.message : 'Unknown error'}`)
  }
}

