/**
 * Ansible Executor
 * Wraps Ansible CLI operations
 */

import { exec } from 'child_process'
import { promisify } from 'util'
import { promises as fs } from 'fs'
import { join } from 'path'
import { logger } from './logger.js'

const execAsync = promisify(exec)

export interface AnsiblePlaybookOptions {
  playbook: string
  inventory?: string
  extraVars?: Record<string, any>
  tags?: string[]
  skipTags?: string[]
  limit?: string
  verbose?: boolean
}

export class AnsibleExecutor {
  /**
   * Check if Ansible is installed
   */
  async checkAnsibleInstalled(): Promise<boolean> {
    try {
      await execAsync('ansible-playbook --version')
      return true
    } catch {
      return false
    }
  }

  /**
   * Run Ansible playbook
   */
  async runPlaybook(options: AnsiblePlaybookOptions): Promise<{ stdout: string; stderr: string }> {
    const args: string[] = [options.playbook]

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

    if (options.extraVars) {
      const vars = Object.entries(options.extraVars)
        .map(([key, value]) => `${key}=${JSON.stringify(value)}`)
        .join(' ')
      args.push('--extra-vars', vars)
    }

    if (options.tags && options.tags.length > 0) {
      args.push('--tags', options.tags.join(','))
    }

    if (options.skipTags && options.skipTags.length > 0) {
      args.push('--skip-tags', options.skipTags.join(','))
    }

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

    if (options.verbose) {
      args.push('-vvv')
    }

    logger.info('Executing Ansible playbook', { playbook: options.playbook })
    return execAsync(`ansible-playbook ${args.join(' ')}`)
  }

  /**
   * Create inventory file
   */
  async createInventory(inventoryPath: string, hosts: Array<{ name: string; host: string; groups?: string[] }>): Promise<void> {
    const inventory: string[] = []

    // Group hosts by group
    const groups: Record<string, string[]> = {}
    for (const host of hosts) {
      if (host.groups && host.groups.length > 0) {
        for (const group of host.groups) {
          if (!groups[group]) {
            groups[group] = []
          }
          groups[group].push(host.name)
        }
      } else {
        if (!groups['ungrouped']) {
          groups['ungrouped'] = []
        }
        groups['ungrouped'].push(host.name)
      }
    }

    // Write groups
    for (const [group, hostNames] of Object.entries(groups)) {
      inventory.push(`[${group}]`)
      for (const hostName of hostNames) {
        const host = hosts.find((h) => h.name === hostName)
        if (host) {
          inventory.push(`${host.name} ansible_host=${host.host}`)
        }
      }
      inventory.push('')
    }

    await fs.writeFile(inventoryPath, inventory.join('\n'), 'utf-8')
  }

  /**
   * Create playbook file
   */
  async createPlaybook(playbookPath: string, playbook: any): Promise<void> {
    const yaml = this.playbookToYAML(playbook)
    await fs.writeFile(playbookPath, yaml, 'utf-8')
  }

  /**
   * Convert playbook object to YAML (simplified)
   */
  private playbookToYAML(playbook: any): string {
    // Simplified YAML generation - in production, use a proper YAML library
    let yaml = '---\n'
    yaml += `- name: ${playbook.name || 'Playbook'}\n`
    yaml += `  hosts: ${playbook.hosts || 'all'}\n`
    
    if (playbook.vars) {
      yaml += '  vars:\n'
      for (const [key, value] of Object.entries(playbook.vars)) {
        yaml += `    ${key}: ${JSON.stringify(value)}\n`
      }
    }

    if (playbook.tasks) {
      yaml += '  tasks:\n'
      for (const task of playbook.tasks) {
        yaml += `    - name: ${task.name}\n`
        yaml += `      ${task.module}: ${JSON.stringify(task.args || {})}\n`
      }
    }

    return yaml
  }
}

export const ansibleExecutor = new AnsibleExecutor()

