/**
 * Helm Executor
 * Wraps Helm CLI operations
 */

import { exec } from 'child_process'
import { promisify } from 'util'
import { logger } from './logger.js'

const execAsync = promisify(exec)

export interface HelmInstallOptions {
  releaseName: string
  chart: string
  namespace?: string
  valuesFile?: string
  values?: Record<string, any>
  version?: string
  wait?: boolean
  timeout?: string
}

export interface HelmUpgradeOptions extends HelmInstallOptions {
  reuseValues?: boolean
}

export class HelmExecutor {
  /**
   * Check if Helm is available
   */
  async checkHelmInstalled(): Promise<boolean> {
    try {
      await execAsync('helm version')
      return true
    } catch {
      return false
    }
  }

  /**
   * Install Helm chart
   */
  async install(options: HelmInstallOptions): Promise<{ stdout: string; stderr: string }> {
    const args: string[] = [
      'install',
      options.releaseName,
      options.chart,
    ]

    if (options.namespace) {
      args.push('--namespace', options.namespace)
    }

    if (options.valuesFile) {
      args.push('--values', options.valuesFile)
    }

    if (options.version) {
      args.push('--version', options.version)
    }

    if (options.wait) {
      args.push('--wait')
    }

    if (options.timeout) {
      args.push('--timeout', options.timeout)
    }

    if (options.values) {
      // Write values to temp file and use --set-file or --set
      // For now, we'll use --set for simple values
      for (const [key, value] of Object.entries(options.values)) {
        args.push('--set', `${key}=${JSON.stringify(value)}`)
      }
    }

    logger.info('Executing Helm install', { args })
    return execAsync(`helm ${args.join(' ')}`)
  }

  /**
   * Upgrade Helm release
   */
  async upgrade(options: HelmUpgradeOptions): Promise<{ stdout: string; stderr: string }> {
    const args: string[] = [
      'upgrade',
      options.releaseName,
      options.chart,
    ]

    if (options.namespace) {
      args.push('--namespace', options.namespace)
    }

    if (options.valuesFile) {
      args.push('--values', options.valuesFile)
    }

    if (options.version) {
      args.push('--version', options.version)
    }

    if (options.wait) {
      args.push('--wait')
    }

    if (options.timeout) {
      args.push('--timeout', options.timeout)
    }

    if (options.reuseValues) {
      args.push('--reuse-values')
    }

    logger.info('Executing Helm upgrade', { args })
    return execAsync(`helm ${args.join(' ')}`)
  }

  /**
   * Uninstall Helm release
   */
  async uninstall(releaseName: string, namespace?: string): Promise<{ stdout: string; stderr: string }> {
    const args: string[] = ['uninstall', releaseName]

    if (namespace) {
      args.push('--namespace', namespace)
    }

    logger.info('Executing Helm uninstall', { args })
    return execAsync(`helm ${args.join(' ')}`)
  }

  /**
   * Get release status
   */
  async status(releaseName: string, namespace?: string): Promise<any> {
    const args: string[] = ['status', releaseName, '--output', 'json']

    if (namespace) {
      args.push('--namespace', namespace)
    }

    try {
      const { stdout } = await execAsync(`helm ${args.join(' ')}`)
      return JSON.parse(stdout)
    } catch (error) {
      logger.error('Failed to get Helm status', { error })
      throw error
    }
  }

  /**
   * List releases
   */
  async list(namespace?: string): Promise<any[]> {
    const args: string[] = ['list', '--output', 'json']

    if (namespace) {
      args.push('--namespace', namespace)
    }

    try {
      const { stdout } = await execAsync(`helm ${args.join(' ')}`)
      return JSON.parse(stdout)
    } catch (error) {
      logger.error('Failed to list Helm releases', { error })
      throw error
    }
  }
}

export const helmExecutor = new HelmExecutor()

