#!/usr/bin/env node

import { program } from 'commander'
import chalk from 'chalk'
import ora from 'ora'
import { spawn } from 'child_process'
import { homedir } from 'os'
import { join } from 'path'
import { FCPClient } from './client.js'
import { formatTable, formatInstance, formatError } from './format.js'

// Validate required environment variables
function checkEnv() {
  // Skip check - client will handle it with better error messages
  // that include Flow config option
}

program
  .name('mithril')
  .description('Minimal IaaS for FCP')
  .version('0.1.0')

program
  .command('list')
  .description('List available instances')
  .option('--mine', 'List my instances')
  .option('--available', 'Only show available instances')
  .action(async (options) => {
    checkEnv()
    const client = new FCPClient()
    
    try {
      if (options.mine) {
        const spinner = ora('Fetching your instances...').start()
        const instances = await client.listMyInstances()
        spinner.stop()
        console.log(formatTable(instances, ['id', 'type', 'status', 'region']))
      } else {
        const spinner = ora('Fetching availability...').start()
        let available = await client.listAvailable()
        spinner.stop()
        
        if (options.available) {
          available = available.filter(a => a.available > 0)
        }
        
        // Sort for consistent output
        available.sort((a, b) => {
          if (a.type !== b.type) return a.type.localeCompare(b.type)
          return a.region.localeCompare(b.region)
        })
        
        console.log(formatTable(available, ['type', 'region', 'gpu', 'price', 'available']))
      }
    } catch (error) {
      console.error(formatError(error))
      process.exit(1)
    }
  })

program
  .command('create <type>')
  .description('Create an instance')
  .option('-r, --region <region>', 'Specific region')
  .action(async (type, options) => {
    checkEnv()
    const client = new FCPClient()
    
    // Query spot availability
    const spinner = ora(`Finding available ${chalk.cyan(type)}...`).start()
    
    try {
      // Fetch current spot prices
      const auctions = await client.listAvailable()
      let candidates = auctions.filter(a => a.type === type)
      if (options.region) {
        candidates = candidates.filter(a => a.region === options.region)
      }
      
      if (candidates.length === 0) {
        spinner.fail(chalk.red(`No availability for ${type}`))
        console.log(chalk.gray('\nTry: mithril list --available'))
        process.exit(1)
      }
      
      const auction = candidates[0]
      spinner.succeed(chalk.green('✓ Found ') + chalk.cyan(type) + ' in ' + chalk.yellow(auction.region) + chalk.gray(` ($${auction.price}/hr)`))
      
      // Execute spot bid
      spinner.start('Submitting bid...')
      const id = await client.createInstance(type, options)
      spinner.succeed(chalk.green('✓ Bid accepted!'))
      
      console.log(`\n${chalk.gray('Instance ID:')} ${chalk.cyan(id)}`)
      console.log(`${chalk.gray('Status:')} ${chalk.yellow('PROVISIONING')}`)
      console.log(`${chalk.gray('Estimated time:')} 8-12 minutes`)
      console.log(chalk.gray('\n📧 You\'ll receive an email from Foundry when your instance is ready'))
      console.log(chalk.gray('Check status:') + ` mithril status ${id}`)
    } catch (error) {
      spinner.fail(formatError(error))
      if (error.message.includes('No availability')) {
        console.log(chalk.gray('\nTry: mithril list --available'))
      }
      process.exit(1)
    }
  })

program
  .command('status <id>')
  .description('Show instance status')
  .action(async (id) => {
    checkEnv()
    const client = new FCPClient()
    
    try {
      const instance = await client.getInstance(id)
      console.log(formatInstance(instance))
    } catch (error) {
      console.error(formatError(error))
      process.exit(1)
    }
  })

program
  .command('ssh <id>')
  .description('SSH to instance')
  .option('-k, --key <path>', 'SSH private key path')
  .action(async (id, options) => {
    checkEnv()
    const client = new FCPClient()
    const spinner = ora('Getting instance details...').start()
    
    try {
      const instance = await client.getInstance(id)
      
      if (instance.status === 'NOT_FOUND') {
        spinner.fail(chalk.red(`Instance not found: ${id}`))
        process.exit(1)
      }
      
      if (!instance.ip) {
        spinner.fail(chalk.red(`Instance ${id} has no IP address yet`))
        process.exit(1)
      }
      
      spinner.stop()
      
      const keyPath = options.key || process.env.FCP_SSH_KEY || join(homedir(), '.ssh', 'id_rsa')
      const sshArgs = [
        '-o', 'StrictHostKeyChecking=no',
        '-o', 'UserKnownHostsFile=/dev/null',
        '-o', 'ConnectTimeout=10',
        '-i', keyPath,
        `ubuntu@${instance.ip}`
      ]
      
      console.log(chalk.gray(`Connecting to ${instance.ip}...`))
      
      // Execute interactive SSH session
      const ssh = spawn('ssh', sshArgs, { stdio: 'inherit' })
      
      ssh.on('exit', (code) => {
        process.exit(code || 0)
      })
    } catch (error) {
      spinner.fail(formatError(error))
      process.exit(1)
    }
  })

program
  .command('delete <id>')
  .description('Delete instance')
  .action(async (id) => {
    checkEnv()
    const client = new FCPClient()
    const spinner = ora(`Deleting instance ${chalk.cyan(id)}...`).start()
    
    try {
      const deleted = await client.deleteInstance(id)
      if (deleted) {
        spinner.succeed(chalk.green('✓ Instance deleted: ') + chalk.cyan(id))
      } else {
        spinner.warn(chalk.yellow('Instance not found: ') + chalk.cyan(id))
      }
    } catch (error) {
      spinner.fail(formatError(error))
      process.exit(1)
    }
  })

// Display help when no command provided
if (process.argv.length === 2) {
  program.outputHelp()
}

program.parse()