import { join } from 'path';
import ora from 'ora';
import chalk from 'chalk';
import { logger } from '../utils/logger.js';
import {
  getContentDir,
  copyDirectory,
  pathExists
} from '../utils/file-copier.js';
import {
  checkCLIOutdated,
  checkProjectOutdated,
  saveProjectMorphVersion,
  getUpdateInstructions,
  detectInstallMethod
} from '../utils/version-checker.js';

export async function updateCommand(options) {
  const targetPath = process.cwd();
  const contentDir = getContentDir();
  const morphPath = join(targetPath, '.morph');

  logger.header('MORPH-SPEC Update');

  // Check if MORPH is initialized
  if (!(await pathExists(morphPath))) {
    logger.error('MORPH not initialized in this directory.');
    logger.dim('Run "morph-spec init" first.');
    process.exit(1);
  }

  // Check CLI version
  const spinner = ora('Checking versions...').start();
  const cliCheck = await checkCLIOutdated();
  const projectCheck = await checkProjectOutdated(targetPath);

  spinner.stop();

  // Display version info
  logger.blank();
  logger.info('Version Status:');
  logger.dim(`  CLI version: ${cliCheck.current}`);

  if (projectCheck.current) {
    logger.dim(`  Project MORPH version: ${projectCheck.current}`);
  } else {
    logger.dim('  Project MORPH version: not found (legacy installation)');
  }

  if (cliCheck.latest) {
    const latestColor = cliCheck.isOutdated ? chalk.yellow : chalk.green;
    logger.dim(`  Latest available: ${latestColor(cliCheck.latest)}`);
  }
  logger.blank();

  // If CLI is outdated, stop and instruct user
  if (cliCheck.isOutdated && cliCheck.latest) {
    logger.warn(`Your CLI is outdated (${cliCheck.current} → ${cliCheck.latest})`);
    logger.blank();
    logger.info('Please update the CLI first:');
    logger.blank();

    const method = detectInstallMethod();
    const instructions = getUpdateInstructions(method);

    instructions.forEach(line => {
      if (line === '') {
        logger.blank();
      } else if (line.startsWith('Or ')) {
        logger.dim(line);
      } else {
        logger.box([line]);
      }
    });

    logger.blank();
    logger.dim('Then run "morph-spec update" again.');
    process.exit(0);
  }

  // Proceed with update
  const updateSpinner = ora('Updating MORPH-SPEC...').start();

  try {
    const updateTemplates = !options.standards || options.templates;
    const updateStandards = !options.templates || options.standards;

    // Update templates
    if (updateTemplates) {
      updateSpinner.text = 'Updating templates...';
      const templatesSrc = join(contentDir, '.morph', 'templates');
      const templatesDest = join(morphPath, 'templates');
      await copyDirectory(templatesSrc, templatesDest);
    }

    // Update standards
    if (updateStandards) {
      updateSpinner.text = 'Updating standards...';
      const standardsSrc = join(contentDir, '.morph', 'standards');
      const standardsDest = join(morphPath, 'standards');
      await copyDirectory(standardsSrc, standardsDest);
    }

    // Update agents.json
    updateSpinner.text = 'Updating agents configuration...';
    const agentsSrc = join(contentDir, '.morph', 'config', 'agents.json');
    const agentsDest = join(morphPath, 'config', 'agents.json');
    if (await pathExists(agentsSrc)) {
      await copyDirectory(agentsSrc, agentsDest);
    }

    // Update .claude commands and skills
    updateSpinner.text = 'Updating Claude commands and skills...';
    const claudeSrc = join(contentDir, '.claude');
    const claudeDest = join(targetPath, '.claude');
    if (await pathExists(claudeSrc)) {
      await copyDirectory(claudeSrc, claudeDest);
    }

    // Update CLAUDE.md
    updateSpinner.text = 'Updating CLAUDE.md...';
    const claudeMdSrc = join(contentDir, 'CLAUDE.md');
    const claudeMdDest = join(targetPath, 'CLAUDE.md');
    await copyDirectory(claudeMdSrc, claudeMdDest);

    // Update .morphversion
    updateSpinner.text = 'Saving version info...';
    await saveProjectMorphVersion(targetPath, cliCheck.current);

    updateSpinner.succeed('MORPH-SPEC updated successfully!');
    logger.blank();

    // Show version change
    if (projectCheck.current && projectCheck.current !== cliCheck.current) {
      logger.success(`Updated: ${projectCheck.current} → ${cliCheck.current}`);
    } else if (!projectCheck.current) {
      logger.success(`Updated to v${cliCheck.current}`);
    } else {
      logger.success(`Already up to date (v${cliCheck.current})`);
    }

    logger.blank();
    logger.info('Updated files:');
    if (updateTemplates) logger.dim('  ✓ .morph/templates/');
    if (updateStandards) logger.dim('  ✓ .morph/standards/');
    logger.dim('  ✓ .morph/config/agents.json');
    logger.dim('  ✓ .claude/commands/ and .claude/skills/');
    logger.dim('  ✓ CLAUDE.md');
    logger.blank();
    logger.info('Your config.json was preserved.');
    logger.dim('Review the updated files for any new features.');
    logger.blank();

  } catch (error) {
    updateSpinner.fail('Update failed');
    logger.error(error.message);
    process.exit(1);
  }
}
