import { readFileSync, existsSync } from 'fs';
import { join } from 'path';
import { execSync } from 'child_process';
import chalk from 'chalk';
import { executeStopHooks, isMaxRetriesExceeded, incrementRetryCount } from '../hooks/stop-hook-executor.js';
import { recordEvent } from '../analytics/analytics-engine.js';
import { getFeature } from '../../core/state/state-manager.js';

/**
 * Checkpoint Hooks - Automated validation orchestration
 *
 * Runs validators, tests, and linters at checkpoint milestones (every N tasks).
 * Blocks progress if critical validations fail.
 */

/**
 * Load LLM interaction configuration
 * @returns {Object} Configuration object
 */
function loadLLMInteractionConfig() {
  const configPath = join(process.cwd(), '.morph/config/llm-interaction.json');

  if (!existsSync(configPath)) {
    // Return defaults if config doesn't exist
    return {
      checkpoints: {
        frequency: 3,
        autoValidate: true,
        validators: {
          enabled: ['architecture', 'packages', 'design-system', 'security'],
          optional: []
        },
        hooks: {
          runTests: false,
          runLinters: true,
          buildCheck: false
        },
        onFailure: {
          blockProgress: true,
          maxRetries: 3,
          escalateAfter: 3
        }
      }
    };
  }

  return JSON.parse(readFileSync(configPath, 'utf8'));
}

/**
 * Run a single validator
 * @param {string} validatorName - Validator to run (architecture, packages, etc.)
 * @param {string} featureName - Feature being validated
 * @returns {Promise<Object>} Validation result
 */
async function runValidator(validatorName, featureName) {
  try {
    // Use existing validate command
    const result = execSync(
      `node bin/validate.js ${validatorName} --feature=${featureName} --json`,
      { encoding: 'utf8', stdio: 'pipe' }
    );

    const parsed = JSON.parse(result);
    return {
      validator: validatorName,
      passed: parsed.errors === 0,
      errors: parsed.errors || 0,
      warnings: parsed.warnings || 0,
      details: parsed.issues || []
    };
  } catch (error) {
    return {
      validator: validatorName,
      passed: false,
      errors: 1,
      warnings: 0,
      details: [{ message: error.message, severity: 'error' }]
    };
  }
}

/**
 * Run tests if configured
 * @param {string} featureName - Feature being tested
 * @returns {Promise<Object>} Test result
 */
async function runTests(featureName) {
  try {
    execSync('npm test --passWithNoTests', { encoding: 'utf8', stdio: 'pipe' });
    return {
      validator: 'tests',
      passed: true,
      errors: 0,
      warnings: 0,
      details: []
    };
  } catch (error) {
    return {
      validator: 'tests',
      passed: false,
      errors: 1,
      warnings: 0,
      details: [{ message: 'Test suite failed', severity: 'error' }]
    };
  }
}

/**
 * Run linters if configured
 * @param {string} featureName - Feature being linted
 * @returns {Promise<Object>} Linter result
 */
async function runLinters(featureName) {
  try {
    // Check if eslint exists
    if (existsSync(join(process.cwd(), 'node_modules/.bin/eslint'))) {
      execSync('npm run lint --if-present', { encoding: 'utf8', stdio: 'pipe' });
    }

    return {
      validator: 'linters',
      passed: true,
      errors: 0,
      warnings: 0,
      details: []
    };
  } catch (error) {
    return {
      validator: 'linters',
      passed: false,
      errors: 0,
      warnings: 1,
      details: [{ message: 'Linting warnings detected', severity: 'warning' }]
    };
  }
}

/**
 * Run checkpoint hooks - orchestrates all validation
 * @param {string} featureName - Feature name
 * @param {number} checkpointNum - Checkpoint number (1, 2, 3, etc.)
 * @returns {Promise<Object>} Checkpoint result
 */
export async function runCheckpointHooks(featureName, checkpointNum) {
  const config = loadLLMInteractionConfig();
  const checkpointConfig = config.checkpoints;

  if (!checkpointConfig.autoValidate) {
    return {
      passed: true,
      skipped: true,
      message: 'Auto-validation disabled in config'
    };
  }

  console.log(`\n🔍 Running CHECKPOINT ${checkpointNum} for feature: ${featureName}`);
  console.log('━'.repeat(60));

  const results = [];

  // 1. Run enabled validators
  console.log('\n📋 Running validators...');
  for (const validatorName of checkpointConfig.validators.enabled) {
    process.stdout.write(`  • ${validatorName}... `);
    const result = await runValidator(validatorName, featureName);
    results.push(result);

    if (result.passed) {
      console.log('✅ PASSED');
    } else {
      console.log(`❌ FAILED (${result.errors} errors, ${result.warnings} warnings)`);
    }
  }

  // 2. Run tests (if configured)
  if (checkpointConfig.hooks.runTests) {
    console.log('\n🧪 Running tests...');
    process.stdout.write('  • test suite... ');
    const testResult = await runTests(featureName);
    results.push(testResult);

    if (testResult.passed) {
      console.log('✅ PASSED');
    } else {
      console.log('❌ FAILED');
    }
  }

  // 3. Run linters (if configured)
  if (checkpointConfig.hooks.runLinters) {
    console.log('\n🎨 Running linters...');
    process.stdout.write('  • code style... ');
    const lintResult = await runLinters(featureName);
    results.push(lintResult);

    if (lintResult.passed) {
      console.log('✅ PASSED');
    } else {
      console.log('⚠️  WARNINGS');
    }
  }

  // Calculate overall pass/fail
  const errorCount = results.reduce((sum, r) => sum + r.errors, 0);
  const warningCount = results.reduce((sum, r) => sum + r.warnings, 0);
  const passed = errorCount === 0;

  console.log('\n' + '━'.repeat(60));
  console.log(`\n📊 Checkpoint ${checkpointNum} Summary:`);
  console.log(`   Errors: ${errorCount}`);
  console.log(`   Warnings: ${warningCount}`);
  console.log(`   Status: ${passed ? '✅ PASSED' : '❌ FAILED'}`);

  if (!passed) {
    console.log('\n⚠️  Checkpoint failed! Fix violations before proceeding.');

    // Show details of failures
    results.filter(r => r.errors > 0).forEach(r => {
      console.log(`\n❌ ${r.validator} errors:`);
      r.details.forEach(d => {
        if (d.severity === 'error') {
          console.log(`   - ${d.message}`);
        }
      });
    });
  }

  console.log('\n' + '━'.repeat(60) + '\n');

  // Run stop hooks for L-Thread support
  let stopHookResult = null;
  if (featureName) {
    try {
      // Use feature name as pseudo thread ID for stop hook feedback
      const pseudoThreadId = `checkpoint-${featureName}-${checkpointNum}`;
      stopHookResult = await executeStopHooks(pseudoThreadId, 'on-stop', { feature: featureName });

      if (!stopHookResult.passed) {
        // Check retry count
        let retryCount = null;
        if (isMaxRetriesExceeded(pseudoThreadId)) {
          console.log(chalk.red('\n❌ Stop hooks failed 5+ times. Escalating to user.'));
        } else {
          retryCount = incrementRetryCount(pseudoThreadId);
          console.log(chalk.yellow(`\n⚠ Stop hooks failed (attempt ${retryCount}/5). Feedback saved.`));
          if (stopHookResult.feedback?.suggestions?.length > 0) {
            stopHookResult.feedback.suggestions.forEach(s => console.log(`  → ${s}`));
          }
        }

        // Record to analytics
        recordEvent({
          type: 'stop_hook_failed_at_checkpoint',
          feature: featureName,
          data: { checkpointNum, retryCount }
        });
      }
    } catch {
      // Stop hooks are non-critical — don't block checkpoint if they error
    }
  }

  const phase = featureName ? (getFeature(featureName)?.phase || null) : null;

  return {
    passed,
    checkpointNum,
    timestamp: new Date().toISOString(),
    phase,
    results,
    summary: {
      errors: errorCount,
      warnings: warningCount,
      validatorsRun: results.length
    }
  };
}

/**
 * Check if checkpoint should run based on task count
 * @param {number} tasksCompleted - Number of tasks completed
 * @param {number} frequency - Checkpoint frequency (default: 3)
 * @returns {boolean} True if checkpoint should run
 */
export function shouldRunCheckpoint(tasksCompleted, frequency = 3) {
  return tasksCompleted > 0 && tasksCompleted % frequency === 0;
}

/**
 * Get checkpoint number from task count
 * @param {number} tasksCompleted - Number of tasks completed
 * @param {number} frequency - Checkpoint frequency (default: 3)
 * @returns {number} Checkpoint number
 */
export function getCheckpointNumber(tasksCompleted, frequency = 3) {
  return Math.floor(tasksCompleted / frequency);
}
