#!/usr/bin/env node

import { program } from 'commander';
import chalk from 'chalk';
import { OptimusAuth } from './auth';
import * as fs from 'fs';
import * as path from 'path';
import * as os from 'os';
import { execSync } from 'child_process';

// Define program version and description
program
  .version('1.0.9')
  .description('Optimus Security Initialization Tool');

// Get command - make a GET request to any endpoint
program
  .command('get <endpoint>')
  .description('Make an authenticated GET request to any endpoint')
  .option('-e, --env <path>', 'Path to optimus.env file', './optimus.env')
  .option('-u, --url <url>', 'Base URL for the API (optional, will use OPTIMUS_ENDPOINT from env file)')
  .option('-p, --params <params>', 'Query parameters in JSON format', '{}')
  .option('-o, --output <file>', 'Save response to file instead of displaying')
  .option('--user <user>', 'Git user name')
  .option('--repo <repo>', 'Git remote output')
  .option('--branch <branch>', 'Git branch name')
  .option('--agent <agent>', 'AI agent name (e.g., Cursor, Claude)')
  .action(async (endpoint, options) => {
    try {
      const auth = new OptimusAuth(options.env, options.url);
      const params = JSON.parse(options.params);
      
      // Add user, repo, branch, and agent to params if provided
      if (options.user) {
        params.user = options.user;
      }
      if (options.repo) {
        params.repo = options.repo;
      }
      if (options.branch) {
        params.branch = options.branch;
      }
      if (options.agent) {
        params.agent = options.agent;
      }
      
      console.log(chalk.blue(`Making authenticated GET request to ${endpoint}...`));
      const response = await auth.get(endpoint, params);
      
      if (options.output) {
        fs.writeFileSync(options.output, JSON.stringify(response, null, 2));
        console.log(chalk.green(`Response saved to ${options.output}`));
      } else {
        console.log(chalk.green('Response:'));
        
        // Output the response as-is, let the shell handle formatting
        const responseStr = typeof response === 'string' ? response : JSON.stringify(response, null, 2);
        console.log(responseStr);
      }
    } catch (err) {
      console.error(chalk.red('Error:'), err);
      process.exit(1);
    }
  });

// Check command - check if this is a Unix-like system with tr available
program
  .command('is-unix')
  .description('Check if this is a Unix-like system with tr available and output true/false')
  .action(() => {
    try {
      const platform = os.platform();
      
      // Check if we're on a Unix-like system and tr is available
      const isUnixLike = ['darwin', 'linux', 'freebsd', 'openbsd'].includes(platform);
      let trAvailable = false;
      
      if (isUnixLike) {
        try {
          execSync('which tr', { stdio: 'ignore' });
          trAvailable = true;
        } catch (err) {
          // tr not available
        }
      }
      
      // Set exit code without exiting: 0 for true, 1 for false
      // On Windows, we'll use Node.js replacement instead of tr
      process.exitCode = trAvailable ? 0 : 1;
    } catch (err) {
      process.exitCode = 1;
    }
  });

// Post command - make a POST request to any endpoint
program
  .command('post <endpoint>')
  .description('Make an authenticated POST request to any endpoint')
  .option('-e, --env <path>', 'Path to optimus.env file', './optimus.env')
  .option('-u, --url <url>', 'Base URL for the API (optional, will use OPTIMUS_ENDPOINT from env file)')
  .option('-d, --data <data>', 'Request body in JSON format', '{}')
  .option('-o, --output <file>', 'Save response to file instead of displaying')
  .action(async (endpoint, options) => {
    try {
      const auth = new OptimusAuth(options.env, options.url);
      const data = JSON.parse(options.data);
      
      console.log(chalk.blue(`Making authenticated POST request to ${endpoint}...`));
      const response = await auth.post(endpoint, data);
      
      if (options.output) {
        fs.writeFileSync(options.output, JSON.stringify(response, null, 2));
        console.log(chalk.green(`Response saved to ${options.output}`));
      } else {
        console.log(chalk.green('Response:'));
        console.log(JSON.stringify(response, null, 2));
      }
    } catch (err) {
      console.error(chalk.red('Error:'), err);
      process.exit(1);
    }
  });

// Download command - download a file from any endpoint
program
  .command('download <endpoint> <outputPath>')
  .description('Download a file from an authenticated endpoint')
  .option('-e, --env <path>', 'Path to optimus.env file', './optimus.env')
  .option('-u, --url <url>', 'Base URL for the API (optional, will use OPTIMUS_ENDPOINT from env file)')
  .option('-p, --params <params>', 'Query parameters in JSON format', '{}')
  .option('--user <user>', 'Git user name')
  .option('--repo <repo>', 'Git remote output')
  .option('--branch <branch>', 'Git branch name')
  .option('--agent <agent>', 'AI agent name (e.g., Cursor, Claude)')
  .action(async (endpoint, outputPath, options) => {
    try {
      const auth = new OptimusAuth(options.env, options.url);
      const params = JSON.parse(options.params);
      
      // Add user, repo, branch, and agent to params if provided
      if (options.user) {
        params.user = options.user;
      }
      if (options.repo) {
        params.repo = options.repo;
      }
      if (options.branch) {
        params.branch = options.branch;
      }
      if (options.agent) {
        params.agent = options.agent;
      }
      
      // Handle URLs that already contain query parameters
      let cleanEndpoint = endpoint;
      let endpointParams = { ...params };
      
      // If the endpoint contains query parameters, extract them and merge with params
      if (endpoint.includes('?')) {
        const [baseEndpoint, queryString] = endpoint.split('?');
        cleanEndpoint = baseEndpoint;
        
        // Parse query string and merge with params
        const urlParams = new URLSearchParams(queryString);
        for (const [key, value] of urlParams.entries()) {
          endpointParams[key] = value;
        }
      }
      
      console.log(chalk.blue(`Downloading from ${cleanEndpoint} to ${outputPath}...`));
      await auth.downloadFile(cleanEndpoint, outputPath, endpointParams);
      console.log(chalk.green('Download complete!'));
    } catch (err) {
      console.error(chalk.red('Error:'), err);
      process.exit(1);
    }
  });

// Init command - initialize Optimus Security configuration
// This is the main command for setting up Optimus Security
program
  .command('init')
  .description('Initialize Optimus Security configuration')
  .option('-e, --env <path>', 'Path to optimus.env file', './optimus.env')
  .option('-u, --url <url>', 'Base URL for the API (optional, will use OPTIMUS_ENDPOINT from env file)')
  .option('-d, --dir <dir>', 'Directory to store config files', './.cursor')
  .action(async (options) => {
    try {
      console.log(chalk.blue('Initializing Optimus Security...'));
      
      const auth = new OptimusAuth(options.env, options.url);
      const cursorDir = options.dir;
      
      // Get server version
      console.log(chalk.blue('Checking server version...'));
      const versionData = await auth.get('/api/mcp/version/');
      console.log(chalk.green(`Server version: ${versionData.version}`));
      
      // Check local version
      let localVersion = '0';
      const mcpJsonPath = path.join(cursorDir, 'mcp.json');
      
      if (fs.existsSync(mcpJsonPath)) {
        try {
          const mcpConfig = JSON.parse(fs.readFileSync(mcpJsonPath, 'utf8'));
          localVersion = mcpConfig?.optimus_config?.version || '0';
          console.log(chalk.blue(`Local version: ${localVersion}`));
        } catch (err) {
          console.log(chalk.yellow('Error reading local version, will re-initialize'));
        }
      }
      
      // Compare versions and initialize if needed
      const needsInit = !fs.existsSync(mcpJsonPath) || parseFloat(localVersion) < parseFloat(versionData.version);
      
      if (needsInit) {
        console.log(chalk.green('Downloading configuration files...'));
        
        // Create cursor directory if needed
        if (!fs.existsSync(cursorDir)) {
          fs.mkdirSync(cursorDir, { recursive: true });
        }
        
        // Get git username
        let username;
        try {
          username = execSync('git config user.name').toString().trim();
        } catch (err) {
          username = 'unknown';
          console.warn(chalk.yellow('Warning: Could not get git username, using "unknown"'));
        }
        
        // Download all required files with consistent timestamp
        const timestamp = Math.floor(Date.now() / 1000).toString();
        
        await auth.downloadFileWithTimestamp(
          '/api/mcp/mcp.json',
          path.join(cursorDir, 'mcp.json'),
          { username },
          timestamp
        );
        console.log(chalk.green('✓ Downloaded mcp.json'));
        
        await auth.downloadFileWithTimestamp(
          '/api/mcp/chat-formatting.mdc',
          path.join(cursorDir, 'chat-formatting.md'),
          {},
          timestamp
        );
        console.log(chalk.green('✓ Downloaded chat-formatting.md'));
        
        await auth.downloadFileWithTimestamp(
          '/api/mcp/mcp_rules.md',
          path.join(cursorDir, 'mcp_rules.md'),
          {},
          timestamp
        );
        console.log(chalk.green('✓ Downloaded mcp_rules.md'));
        
        console.log(chalk.green('\nOptimus Security has been successfully initialized.'));
      } else {
        console.log(chalk.green('Optimus Security is up to date.'));
      }
    } catch (err) {
      console.error(chalk.red('Error:'), err);
      process.exit(1);
    }
  });

// Parse command line arguments
program.parse(process.argv);

// If no arguments, display help
if (!process.argv.slice(2).length) {
  program.outputHelp();
}