/**
 * MORPH-SPEC Phase Advance Command
 *
 * Validates current phase → advances to next → shows requirements.
 * Replaces the two-step `state set` + `validate-phase` dance.
 *
 * Usage:
 *   morph-spec phase advance <feature>
 *   morph-spec phase advance <feature> --skip-optional
 */

import chalk from 'chalk';
import { loadState, saveState, getFeature, getApprovalGate } from '../../core/state/state-manager.js';
import { PHASES, validatePhase } from './validate-phase.js';
import { detectDesignSystem, hasUIAgentsActive } from '../../lib/detectors/design-system-detector.js';
import { shouldAutoApprove, autoCalculateTrust } from '../../lib/trust/trust-manager.js';
import { validateSpec } from '../../lib/validators/spec-validator.js';
import { validateTransition, getPhaseDisplayName } from '../../core/state/phase-state-machine.js';
import { validateSpecContent, validateTasksContent, validateFeatureOutputs } from '../../lib/validators/content/content-validator.js';
import { getWorkflowConfig } from '../../core/workflows/workflow-detector.js';
import { readFileSync, existsSync } from 'fs';
import { join, dirname } from 'path';
import { fileURLToPath } from 'url';

const __dirname = dirname(fileURLToPath(import.meta.url));

// Phase order for advancing (skips optional phases unless active)
const PHASE_ORDER = ['proposal', 'setup', 'uiux', 'design', 'clarify', 'tasks', 'implement', 'sync'];

/**
 * Get the next phase after the current one
 */
function getNextPhase(currentPhase, feature, skipOptional, featureName) {
  // Load workflow config if workflow is set
  let workflowConfig = null;
  if (feature.workflow && feature.workflow !== 'auto') {
    workflowConfig = getWorkflowConfig(feature.workflow);
  }

  const currentIndex = PHASE_ORDER.indexOf(currentPhase);
  if (currentIndex === -1 || currentIndex >= PHASE_ORDER.length - 1) {
    return null;
  }

  for (let i = currentIndex + 1; i < PHASE_ORDER.length; i++) {
    const candidate = PHASE_ORDER[i];
    const phaseDef = PHASES[candidate];

    // === Workflow-Based Phase Skipping ===
    if (workflowConfig && workflowConfig.phases) {
      // Check if workflow explicitly skips this phase
      if (workflowConfig.phases.skip && workflowConfig.phases.skip.includes(candidate)) {
        console.log(chalk.gray(`  ⏩ Skipping ${candidate}: workflow ${feature.workflow} skips this phase`));
        continue;
      }

      // Check if this phase is part of a combined phase
      if (workflowConfig.phases.combined) {
        for (const [combinedName, phases] of Object.entries(workflowConfig.phases.combined)) {
          if (phases.includes(candidate) && candidate !== combinedName) {
            console.log(chalk.gray(`  ⏩ Skipping ${candidate}: combined into ${combinedName} phase`));
            continue;
          }
        }
      }

      // Check if workflow only runs specific phases
      if (workflowConfig.phases.run && !workflowConfig.phases.run.includes(candidate)) {
        // Also check if it's not a combined phase
        const isCombinedPhase = workflowConfig.phases.combined &&
          Object.keys(workflowConfig.phases.combined).includes(candidate);
        if (!isCombinedPhase) {
          console.log(chalk.gray(`  ⏩ Skipping ${candidate}: not in workflow run list`));
          continue;
        }
      }

      // Check conditional skips
      if (workflowConfig.phases.skipIfCondition) {
        const condition = workflowConfig.phases.skipIfCondition[candidate];
        if (condition) {
          // Evaluate condition (simple conditions for now)
          if (condition === '!hasUIAgents' && !hasUIAgentsActive(process.cwd(), featureName)) {
            console.log(chalk.gray(`  ⏩ Skipping ${candidate}: no UI agents active`));
            continue;
          }
        }
      }
    }

    // === Legacy Phase Skipping (fallback when no workflow config) ===
    if (!workflowConfig) {
      // Skip optional phases if flag set or no relevant agents/outputs
      if (phaseDef?.optional && skipOptional) {
        continue;
      }

      // Skip uiux if no UI agents are active
      if (candidate === 'uiux') {
        const uiAgents = ['blazor-builder', 'uiux-designer', 'nextjs-expert', 'ui-ux-designer'];
        const hasUiAgent = feature.activeAgents?.some(a => uiAgents.includes(a));
        if (!hasUiAgent && skipOptional !== false) {
          console.log(chalk.gray(`  ⏩ Skipping ${candidate}: no UI agents active`));
          continue;
        }
      }

      // Skip sync for simple workflows
      if (candidate === 'sync') {
        const isSimple = feature.workflow === 'fast-track';
        if (isSimple && skipOptional !== false) {
          console.log(chalk.gray(`  ⏩ Skipping ${candidate}: fast-track workflow`));
          continue;
        }
      }
    }

    return candidate;
  }

  return null;
}

/**
 * Main command handler
 */
export async function advancePhaseCommand(feature, options = {}) {
  console.log(chalk.cyan('\n╔════════════════════════════════════════════════╗'));
  console.log(chalk.cyan('║     MORPH-SPEC PHASE ADVANCE                   ║'));
  console.log(chalk.cyan('╚════════════════════════════════════════════════╝\n'));

  // Get current feature state
  const featureData = getFeature(feature);
  if (!featureData) {
    console.log(chalk.red(`✗ Feature not found: ${feature}`));
    console.log(chalk.yellow(`  Run: morph-spec state set ${feature} phase proposal`));
    process.exit(1);
  }

  const currentPhase = featureData.phase;
  const currentPhaseDef = PHASES[currentPhase];

  console.log(chalk.gray('Feature:'), feature);
  console.log(chalk.gray('Current Phase:'), currentPhaseDef?.name || currentPhase);
  console.log(chalk.gray('Workflow:'), featureData.workflow || 'auto');

  // Determine next phase
  const nextPhase = getNextPhase(currentPhase, featureData, options.skipOptional, feature);

  if (!nextPhase) {
    console.log(chalk.green('\n✓ Feature is at the final phase!'));
    if (currentPhase === 'implement' || currentPhase === 'sync') {
      console.log(chalk.green('  Consider running: morph-spec generate recap ' + feature));
    }
    return;
  }

  const nextPhaseDef = PHASES[nextPhase];
  console.log(chalk.gray('Next Phase:'), nextPhaseDef.name);

  // === GATE 1: State Machine Validation ===
  // Ensure phase transition is valid (no skipping required phases)
  if (!options.force) {
    try {
      validateTransition(currentPhase, nextPhase);
    } catch (error) {
      console.log(chalk.red('\n✗ Invalid phase transition'));
      console.log(chalk.yellow(error.message));
      console.log(chalk.gray('\nUse --force to override (not recommended)\n'));
      process.exit(1);
    }
  }

  // === GATE 2: Approval Gate Check ===
  // Check if current phase requires approval before advancing
  const approvalGateMap = {
    'design': 'design',
    'tasks': 'tasks',
    'uiux': 'uiux'
  };

  const requiredGate = approvalGateMap[currentPhase];
  if (requiredGate && !options.skipApproval) {
    const gateStatus = getApprovalGate(feature, requiredGate);

    // Check trust-based auto-approval before blocking
    if (!gateStatus || !gateStatus.approved) {
      try {
        const trustResult = shouldAutoApprove(feature, requiredGate);
        if (trustResult.autoApprove) {
          console.log(chalk.green(`\n✓ Auto-approved gate "${requiredGate}" (${trustResult.reason})`));
          // Proceed — trust bypasses manual gate requirement
        } else {
          console.log(chalk.red(`\n✗ Phase "${currentPhase}" requires approval before advancing`));
          console.log(chalk.gray(`   Trust level: ${trustResult.level} (${trustResult.reason})`));
          console.log(chalk.yellow(`\nRun: morph-spec approve ${feature} ${requiredGate}`));
          console.log(chalk.gray('Or use --skip-approval to bypass (not recommended)\n'));
          process.exit(1);
        }
      } catch {
        // Trust manager unavailable — fall through to manual gate check
        console.log(chalk.red(`\n✗ Phase "${currentPhase}" requires approval before advancing`));
        console.log(chalk.yellow(`\nRun: morph-spec approve ${feature} ${requiredGate}`));
        console.log(chalk.gray('Or use --skip-approval to bypass (not recommended)\n'));
        process.exit(1);
      }
    } else {
      console.log(chalk.green(`✓ Approval gate "${requiredGate}" passed`));
    }
  }

  // === GATE 3: Output Requirements ===
  // Validate that current phase requirements are met before advancing
  const validation = validatePhase(feature, nextPhase);

  if (!validation.valid) {
    console.log(chalk.red('\n✗ Cannot advance — missing requirements:'));
    validation.missingOutputs.forEach(output => {
      console.log(chalk.red(`  - ${output}`));
    });
    console.log(chalk.yellow(`\n  Complete these before advancing to ${nextPhaseDef.name}`));
    process.exit(1);
  }

  if (validation.stateWarning) {
    console.log(chalk.yellow(`\n⚠️  ${validation.stateWarning}`));
  }

  // === GATE 4: Content Validation ===
  // Validate spec.md and contracts.cs when advancing from design phase
  if (currentPhase === 'design' && (nextPhase === 'clarify' || nextPhase === 'tasks')) {
    // Check spec.md structure and content
    if (featureData.outputs?.spec?.created) {
      const specContentValidation = validateSpecContent(featureData.outputs.spec.path);

      if (!specContentValidation.valid) {
        console.log(chalk.red('\n✗ Spec content validation failed:'));
        specContentValidation.missing.forEach(section => {
          console.log(chalk.red(`  - Missing section: ${section}`));
        });
        specContentValidation.errors.forEach(error => {
          console.log(chalk.red(`  - ${error}`));
        });
        console.log('');
        process.exit(1);
      }

      if (specContentValidation.warnings?.length > 0 && !options.skipWarnings) {
        console.log(chalk.yellow('\n⚠️  Spec content warnings:'));
        specContentValidation.warnings.forEach(warning => {
          console.log(chalk.yellow(`  - ${warning}`));
        });
      }
    }

    // Run existing spec validator (anti-patterns, IaC checks)
    const specValidation = await validateSpec('.', feature);

    if (specValidation.errors > 0) {
      console.log(chalk.red('\n✗ Spec validation failed — fix errors before advancing:'));
      specValidation.issues.filter(i => i.level === 'error').forEach(issue => {
        console.log(chalk.red(`  - ${issue.message}`));
        console.log(chalk.yellow(`    → ${issue.solution}`));
      });
      console.log('');
      process.exit(1);
    }

    if (specValidation.warnings > 0 && !options.skipWarnings) {
      console.log(chalk.yellow('\n⚠️  Spec validation warnings:'));
      specValidation.issues.filter(i => i.level === 'warning').forEach(issue => {
        console.log(chalk.yellow(`  - ${issue.message}`));
      });
      console.log(chalk.gray('\n  (Use --skip-warnings to ignore warnings)\n'));
    }
  }

  // === GATE 5: Tasks Content Validation ===
  // Validate tasks.json structure when advancing to implement
  if (currentPhase === 'tasks' && nextPhase === 'implement') {
    if (featureData.outputs?.tasks?.created) {
      const tasksContentValidation = validateTasksContent(featureData.outputs.tasks.path);

      if (!tasksContentValidation.valid) {
        console.log(chalk.red('\n✗ Tasks content validation failed:'));
        tasksContentValidation.errors.forEach(error => {
          console.log(chalk.red(`  - ${error}`));
        });
        console.log('');
        process.exit(1);
      }

      if (tasksContentValidation.warnings?.length > 0 && !options.skipWarnings) {
        console.log(chalk.yellow('\n⚠️  Tasks content warnings:'));
        tasksContentValidation.warnings.forEach(warning => {
          console.log(chalk.yellow(`  - ${warning}`));
        });
      }

      // Show tasks stats
      console.log(chalk.green(`\n✓ Tasks validated: ${tasksContentValidation.stats.totalTasks} total (${tasksContentValidation.stats.regularTasks} tasks + ${tasksContentValidation.stats.checkpoints} checkpoints)`));
    }
  }

  // Gate: Check design system when advancing to implement with UI agents
  if (nextPhase === 'implement') {
    const gateResult = designSystemGate(feature, process.cwd());

    if (gateResult.blocked) {
      console.log(chalk.red(`\n✗ ${gateResult.message}`));
      console.log('');
      gateResult.solution.forEach(line => {
        if (line === '') {
          console.log('');
        } else {
          console.log(chalk.yellow(`  ${line}`));
        }
      });
      console.log('');
      process.exit(1);
    }
  }

  // Advance the phase
  const state = loadState();
  state.features[feature].phase = nextPhase;
  state.features[feature].updatedAt = new Date().toISOString();
  saveState(state);

  // Run PhaseAdvanced agent-teams hook (non-blocking)
  try {
    const { executeHook, formatHookResults } = await import('../../lib/hooks/hook-executor.js');
    const hookResult = await executeHook(process.cwd(), feature, 'PhaseAdvanced', {
      fromPhase: currentPhase,
      toPhase: nextPhase
    });
    if (!hookResult.passed && hookResult.errors.length > 0) {
      const output = formatHookResults(hookResult, 'PhaseAdvanced');
      console.log(output);
    }
  } catch {
    // Hook executor unavailable — non-blocking
  }

  console.log(chalk.green(`\n✓ Advanced to ${nextPhaseDef.name}`));

  // Show what's needed in the new phase
  console.log(chalk.cyan('\n📋 Phase requirements:'));
  console.log(chalk.gray(`   ${nextPhaseDef.description}`));

  if (nextPhaseDef.requiredOutputs?.length > 0) {
    console.log(chalk.cyan('\n   Required outputs:'));
    nextPhaseDef.requiredOutputs.forEach(output => {
      const exists = validation.phase ? true : false; // Already validated
      console.log(chalk.gray(`   ✓ ${output} (exists)`));
    });
  }

  // Show phase-specific guidance
  const guidance = getPhaseGuidance(nextPhase, feature);
  if (guidance) {
    console.log(chalk.cyan('\n   Next steps:'));
    guidance.forEach(step => console.log(chalk.white(`   → ${step}`)));
  }

  console.log('');
}

/**
 * Get guidance for what to do in a phase
 */
function getPhaseGuidance(phase, feature) {
  const guides = {
    'setup': [
      `Resume spec pipeline: /morph-proposal ${feature}`,
      'Auto-continues from setup phase'
    ],
    'uiux': [
      `Resume spec pipeline: /morph-proposal ${feature}`,
      'Provide layout references and preferences',
      'Review wireframes before proceeding'
    ],
    'design': [
      `Resume spec pipeline: /morph-proposal ${feature}`,
      'Review DECISION POINTS carefully',
      'Approve spec.md and contracts.cs'
    ],
    'clarify': [
      `Resume spec pipeline: /morph-proposal ${feature}`,
      'Resolve edge cases and unknowns'
    ],
    'tasks': [
      `Resume spec pipeline: /morph-proposal ${feature}`,
      'Review task order and dependencies',
      'Approve task list before implementing'
    ],
    'implement': [
      `Start implementing: /morph-apply ${feature}`,
      'Complete tasks one by one with: morph-spec task done',
      'Validators run automatically on task completion'
    ],
    'sync': [
      'Review decisions.md for standards to promote',
      `Sync: morph-spec sync --path .morph/project/outputs/${feature}/decisions.md`
    ]
  };

  return guides[phase] || null;
}

/**
 * Gate: Check design system exists when advancing to implement with UI agents
 * @param {string} feature - Feature name
 * @param {string} projectPath - Project root path
 * @returns {Object} { blocked: boolean, message?: string, solution?: string[] }
 */
function designSystemGate(feature, projectPath = '.') {
  // Check if UI agents are active
  const hasUIAgents = hasUIAgentsActive(projectPath, feature);

  if (!hasUIAgents) {
    return { blocked: false }; // No UI agents, gate doesn't apply
  }

  // Check if design system exists
  const dsDetection = detectDesignSystem(projectPath, feature);

  if (dsDetection.hasDesignSystem) {
    return { blocked: false }; // Design system exists, gate passed
  }

  // Block advancement - no design system found with UI agents active
  return {
    blocked: true,
    message: 'Cannot advance to implementation — UI agents are active but no design system found',
    solution: [
      'Design system is required when UI agents (blazor-builder, ui-designer, css-specialist) are active',
      '',
      'Create a design system with one of these options:',
      '  1. Project-level: .morph/project/design-system.md (shared across features)',
      `  2. Feature-level: .morph/project/outputs/${feature}/ui-design-system.md (feature-specific)`,
      '  3. Auto-generate: morph-spec generate design-system (scans existing CSS)',
      '',
      'Or remove UI agents if they are not needed:',
      `  morph-spec state remove-agent ${feature} blazor-builder`
    ]
  };
}
