/**
 * @fileoverview UserReview - Prompts user for approval of generated configs
 * @module morph-spec/ui/user-review
 */

import inquirer from 'inquirer';
import chalk from 'chalk';
import { displayDiff, displayConfigSummary } from './diff-display.js';
import { writeFile, readFile, access } from 'fs/promises';
import { join } from 'path';
import { execSync } from 'child_process';
import { tmpdir } from 'os';

/**
 * @typedef {import('../types/index.js').GeneratedConfigs} GeneratedConfigs
 * @typedef {import('../types/index.js').ProjectConfig} ProjectConfig
 * @typedef {import('../types/index.js').ApprovalResponse} ApprovalResponse
 */

/**
 * UserReview - Handles user review and approval of generated configs
 * @class
 */
export class UserReview {
  /**
   * Prompt user for approval of generated configs
   * @param {GeneratedConfigs} configs - Generated configs
   * @param {ProjectConfig} projectConfig - Detected project config
   * @param {Object} [existingConfigs] - Existing configs (if updating)
   * @returns {Promise<ApprovalResponse>}
   */
  async promptForApproval(configs, projectConfig, existingConfigs = null) {
    console.log(chalk.bold.cyan('\n🔍 Auto-Detected Project Configuration\n'));

    // Display summary
    this.displayPreview(projectConfig);

    // If updating existing configs, show diff
    if (existingConfigs) {
      if (existingConfigs.projectMd) {
        displayDiff(existingConfigs.projectMd, configs.projectMd, 'project.md');
      }
      if (existingConfigs.configJson) {
        try {
          const oldConfig = JSON.parse(existingConfigs.configJson);
          displayConfigSummary(oldConfig, configs.configObject);
        } catch (error) {
          // Couldn't parse old config, skip summary
        }
      }
    }

    // Prompt for action
    const { action } = await inquirer.prompt([
      {
        type: 'list',
        name: 'action',
        message: 'What would you like to do?',
        choices: [
          { name: '✅ Approve and save configs', value: 'approve' },
          { name: '✏️  Edit configs before saving', value: 'edit' },
          { name: '❌ Cancel and exit', value: 'cancel' }
        ],
        default: 'approve'
      }
    ]);

    switch (action) {
      case 'approve':
        return { action: 'approve' };

      case 'edit':
        const editedConfigs = await this.openInEditor(configs);
        return { action: 'approve', editedConfigs };

      case 'cancel':
        const { reason } = await inquirer.prompt([
          {
            type: 'input',
            name: 'reason',
            message: 'Why are you canceling? (optional)',
            default: 'User canceled'
          }
        ]);
        return { action: 'cancel', cancelReason: reason };

      default:
        return { action: 'cancel', cancelReason: 'Unknown action' };
    }
  }

  /**
   * Display preview of detected configuration
   * @param {ProjectConfig} projectConfig - Detected project config
   */
  displayPreview(projectConfig) {
    console.log(chalk.bold('  Name:        ') + chalk.cyan(projectConfig.name));
    console.log(chalk.bold('  Type:        ') + chalk.yellow(projectConfig.type));
    console.log(chalk.bold('  Description: ') + chalk.white(projectConfig.description));
    console.log();

    console.log(chalk.bold('  Stack:'));
    if (projectConfig.stack.frontend) {
      console.log(chalk.gray('    Frontend:  ') + chalk.white(`${projectConfig.stack.frontend.tech} ${projectConfig.stack.frontend.version}`));
    }
    console.log(chalk.gray('    Backend:   ') + chalk.white(`${projectConfig.stack.backend.tech} ${projectConfig.stack.backend.version}`));
    if (projectConfig.stack.database) {
      console.log(chalk.gray('    Database:  ') + chalk.white(`${projectConfig.stack.database.tech} ${projectConfig.stack.database.version}`));
    }
    if (projectConfig.stack.hosting) {
      console.log(chalk.gray('    Hosting:   ') + chalk.white(projectConfig.stack.hosting));
    }
    console.log();

    console.log(chalk.bold('  Architecture: ') + chalk.magenta(projectConfig.architecture));
    console.log(chalk.bold('  Conventions:  ') + chalk.white(projectConfig.conventions));
    console.log();

    // Infrastructure flags
    const flags = [];
    if (projectConfig.hasAzure) flags.push(chalk.blue('Azure'));
    if (projectConfig.hasDocker) flags.push(chalk.cyan('Docker'));
    if (projectConfig.hasDevOps) flags.push(chalk.green('CI/CD'));

    if (flags.length > 0) {
      console.log(chalk.bold('  Infrastructure: ') + flags.join(' • '));
      console.log();
    }

    // Confidence and warnings
    const confidenceColor = projectConfig.confidence >= 90 ? chalk.green : projectConfig.confidence >= 70 ? chalk.yellow : chalk.red;
    console.log(chalk.bold('  Confidence: ') + confidenceColor(`${projectConfig.confidence}%`));

    if (projectConfig.warnings && projectConfig.warnings.length > 0) {
      console.log(chalk.bold.yellow('\n  ⚠️  Warnings:'));
      projectConfig.warnings.forEach(warning => {
        console.log(chalk.yellow(`    • ${warning}`));
      });
    }

    console.log();
  }

  /**
   * Display diff between current and generated configs
   * @param {string} current - Current config content
   * @param {string} generated - Generated config content
   */
  displayDiff(current, generated) {
    displayDiff(current, generated, 'config');
  }

  /**
   * Open configs in editor for manual editing
   * @param {GeneratedConfigs} configs - Configs to edit
   * @returns {Promise<GeneratedConfigs>} Edited configs
   */
  async openInEditor(configs) {
    console.log(chalk.cyan('\n📝 Opening configs in editor...\n'));

    // Write to temp files
    const tempDir = tmpdir();
    const projectMdPath = join(tempDir, 'morph-project.md');
    const configJsonPath = join(tempDir, 'morph-config.json');

    await Promise.all([
      writeFile(projectMdPath, configs.projectMd, 'utf-8'),
      writeFile(configJsonPath, configs.configJson, 'utf-8')
    ]);

    // Get editor from environment or use default
    const editor = process.env.EDITOR || process.env.VISUAL || 'nano';

    console.log(chalk.dim(`  Using editor: ${editor}`));
    console.log(chalk.dim(`  Files: ${projectMdPath}, ${configJsonPath}`));
    console.log(chalk.yellow('\n  Press ENTER when done editing...'));

    // Open editor (blocking)
    try {
      execSync(`${editor} "${projectMdPath}" "${configJsonPath}"`, {
        stdio: 'inherit'
      });
    } catch (error) {
      console.log(chalk.yellow('\n⚠️  Editor exited with error, using original configs\n'));
      return configs;
    }

    // Read edited files
    const [editedProjectMd, editedConfigJson] = await Promise.all([
      readFile(projectMdPath, 'utf-8'),
      readFile(configJsonPath, 'utf-8')
    ]);

    // Parse config.json
    let editedConfigObject;
    try {
      editedConfigObject = JSON.parse(editedConfigJson);
    } catch (error) {
      console.log(chalk.red('\n❌ Edited config.json is not valid JSON. Using original.\n'));
      return configs;
    }

    console.log(chalk.green('\n✅ Configs edited successfully\n'));

    return {
      projectMd: editedProjectMd,
      configJson: editedConfigJson,
      configObject: editedConfigObject
    };
  }
}
