import type { FastifyBaseLogger } from 'fastify';
import { KubernetesClient, type DeploymentSpec } from './client.js';
import type { UserLicense } from '../types/user.js';

export interface ContainerManagerConfig {
  k8sClient: KubernetesClient;
  agentImage: string;
  sidecarImage: string;
  storageClass: string;
  namespace: string;
  logger: FastifyBaseLogger;
}

export interface ContainerStatus {
  exists: boolean;
  ready: boolean;
  mcpEndpoint: string;
}

/**
 * Container manager orchestrates agent container lifecycle
 */
export class ContainerManager {
  private config: ContainerManagerConfig;

  constructor(config: ContainerManagerConfig) {
    this.config = config;
  }

  /**
   * Ensure user's container is running and ready
   * Returns the MCP endpoint URL
   */
  async ensureContainerRunning(
    userId: string,
    license: UserLicense
  ): Promise<{ mcpEndpoint: string; wasCreated: boolean }> {
    const deploymentName = KubernetesClient.getDeploymentName(userId);
    const mcpEndpoint = KubernetesClient.getMcpEndpoint(userId, this.config.namespace);

    this.config.logger.info(
      { userId, licenseType: license.licenseType, deploymentName },
      'Ensuring container is running'
    );

    // Check if deployment already exists
    const exists = await this.config.k8sClient.deploymentExists(deploymentName);

    if (exists) {
      this.config.logger.info({ userId, deploymentName }, 'Container deployment already exists');

      // Wait for it to be ready (in case it's starting up)
      const ready = await this.config.k8sClient.waitForDeploymentReady(deploymentName, 30000);

      if (!ready) {
        this.config.logger.warn(
          { userId, deploymentName },
          'Existing deployment not ready within timeout'
        );
        // Continue anyway - might be an image pull or other transient issue
      }

      return { mcpEndpoint, wasCreated: false };
    }

    // Create new deployment
    this.config.logger.info({ userId, licenseType: license.licenseType }, 'Creating new container');

    const spec: DeploymentSpec = {
      userId,
      licenseType: license.licenseType,
      agentImage: this.config.agentImage,
      sidecarImage: this.config.sidecarImage,
      storageClass: this.config.storageClass,
    };

    await this.config.k8sClient.createAgentDeployment(spec);

    // Wait for deployment to be ready
    const ready = await this.config.k8sClient.waitForDeploymentReady(deploymentName, 120000);

    if (!ready) {
      throw new Error(
        `Container deployment failed to become ready within timeout: ${deploymentName}`
      );
    }

    this.config.logger.info({ userId, mcpEndpoint }, 'Container is ready');

    return { mcpEndpoint, wasCreated: true };
  }

  /**
   * Check container status without creating it
   */
  async getContainerStatus(userId: string): Promise<ContainerStatus> {
    const deploymentName = KubernetesClient.getDeploymentName(userId);
    const mcpEndpoint = KubernetesClient.getMcpEndpoint(userId, this.config.namespace);

    const exists = await this.config.k8sClient.deploymentExists(deploymentName);

    if (!exists) {
      return { exists: false, ready: false, mcpEndpoint };
    }

    // Check if ready (with short timeout)
    const ready = await this.config.k8sClient.waitForDeploymentReady(deploymentName, 5000);

    return { exists: true, ready, mcpEndpoint };
  }

  /**
   * Delete container (for cleanup/testing)
   */
  async deleteContainer(userId: string): Promise<void> {
    await this.config.k8sClient.deleteAgentDeployment(userId);
  }
}
