/**
 * Show command
 * Shows details of a specific commit
 */

import * as path from 'path';
import * as fs from 'fs';
import chalk from 'chalk';
import { CommitManager } from '../../commit/commit-manager';
import { DiffChange } from '../../commit/types';

interface ShowOptions {
  stat?: boolean;
}

export async function showCommand(hash: string, options: ShowOptions) {
  try {
    const projectRoot = process.cwd();

    // Check if .bangstack exists
    const bangstackPath = path.join(projectRoot, '.bangstack');
    if (!fs.existsSync(bangstackPath)) {
      console.error(chalk.red('✗ Error:'), 'Not a Bangstack project. Run "bangstack init" first.');
      process.exit(1);
    }

    // Create commit manager
    const commitManager = new CommitManager(projectRoot);

    // Get commit with diff
    const result = commitManager.showCommitDiff(hash);

    if (!result) {
      console.error(chalk.red('✗ Error:'), `Commit not found: ${hash}`);
      process.exit(1);
    }

    const { commit, summary } = result;

    // Show commit info
    console.log(chalk.yellow('commit'), chalk.cyan(commit.hash));
    if (commit.parent) {
      console.log(chalk.bold('Parent:'), chalk.dim(commit.parent));
    }
    console.log(chalk.bold('Author:'), commit.author);
    console.log(chalk.bold('Date:'), new Date(commit.timestamp).toLocaleString());
    console.log();
    console.log('   ', commit.message);
    console.log();

    // Show summary
    console.log(chalk.bold('Changes:'));
    console.log(chalk.green(`  ${summary.added} added`));
    console.log(chalk.yellow(`  ${summary.modified} modified`));
    console.log(chalk.red(`  ${summary.removed} removed`));
    console.log();

    // Show detailed diff unless --stat
    if (!options.stat) {
      console.log(chalk.bold('Diff:'));
      commit.diff.forEach(change => {
        displayDiffChange(change);
      });
      console.log();
    }

    // Show affected files
    if (commit.filesAffected && commit.filesAffected.length > 0) {
      console.log(chalk.bold('Affected files:'));
      commit.filesAffected.forEach(file => {
        console.log(chalk.dim(`  ${file}`));
      });
      console.log();
    }

    // Show referenced files (from $ref)
    if (commit.referencedFiles && commit.referencedFiles.length > 0) {
      console.log(chalk.bold('Referenced files:'));
      commit.referencedFiles.forEach(file => {
        console.log(chalk.dim(`  ${file}`));
      });
      console.log();
    }

  } catch (error) {
    if (error instanceof Error) {
      console.error(chalk.red('Error:'), error.message);
    } else {
      console.error(chalk.red('Error:'), String(error));
    }

    process.exit(1);
  }
}

function displayDiffChange(change: DiffChange): void {
  const formatValue = (value: any): string => {
    if (typeof value === 'object') {
      return JSON.stringify(value, null, 2).split('\n').map((line, i) =>
        i === 0 ? line : '    ' + line
      ).join('\n');
    }
    return String(value);
  };

  switch (change.op) {
    case 'add':
      console.log(chalk.green(`  + ${change.path}`));
      console.log(chalk.dim(`    ${formatValue(change.value)}`));
      break;

    case 'remove':
      console.log(chalk.red(`  - ${change.path}`));
      console.log(chalk.dim(`    ${formatValue(change.oldValue)}`));
      break;

    case 'modify':
      console.log(chalk.yellow(`  ~ ${change.path}`));
      console.log(chalk.red(`    - ${formatValue(change.oldValue)}`));
      console.log(chalk.green(`    + ${formatValue(change.value)}`));
      break;
  }
}
