/**
 * Phase State Machine - Enforces valid phase transitions
 *
 * Prevents invalid workflow jumps and ensures sequential phase progression.
 * Based on the MORPH 5-phase workflow.
 */

/**
 * Valid phase transitions map
 * Each phase can only transition to specific next phases
 */
const VALID_TRANSITIONS = {
  'proposal': ['setup'],
  'setup': ['uiux', 'design'], // Can skip UI/UX if no frontend
  'uiux': ['design'],
  'design': ['clarify'],
  'clarify': ['tasks'],
  'tasks': ['implement'],
  'implement': ['sync', 'archived'], // Can skip sync
  'sync': ['archived']
};

/**
 * Phase display names for error messages
 */
const PHASE_NAMES = {
  'proposal': 'Proposal (Phase 0)',
  'setup': 'Setup (Phase 1)',
  'uiux': 'UI/UX Design (Phase 1.5)',
  'design': 'Design (Phase 2)',
  'clarify': 'Clarify (Phase 3)',
  'tasks': 'Tasks (Phase 4)',
  'implement': 'Implement (Phase 5)',
  'sync': 'Sync (Phase 6)',
  'archived': 'Archived'
};

/**
 * Optional phases that can be skipped
 */
const OPTIONAL_PHASES = ['uiux', 'sync'];

/**
 * Validate if a phase transition is allowed
 * @param {string} fromPhase - Current phase
 * @param {string} toPhase - Target phase
 * @returns {boolean} True if transition is valid
 */
export function isValidTransition(fromPhase, toPhase) {
  if (!fromPhase || !toPhase) {
    return false;
  }

  const validNextPhases = VALID_TRANSITIONS[fromPhase];
  return validNextPhases ? validNextPhases.includes(toPhase) : false;
}

/**
 * Get list of valid next phases for a given phase
 * @param {string} currentPhase - Current phase
 * @returns {string[]} Array of valid next phase names
 */
export function getValidNextPhases(currentPhase) {
  return VALID_TRANSITIONS[currentPhase] || [];
}

/**
 * Get display name for a phase
 * @param {string} phase - Phase identifier
 * @returns {string} Human-readable phase name
 */
export function getPhaseDisplayName(phase) {
  return PHASE_NAMES[phase] || phase;
}

/**
 * Check if a phase is optional
 * @param {string} phase - Phase identifier
 * @returns {boolean} True if phase is optional
 */
export function isOptionalPhase(phase) {
  return OPTIONAL_PHASES.includes(phase);
}

/**
 * Validate transition and throw error if invalid
 * @param {string} fromPhase - Current phase
 * @param {string} toPhase - Target phase
 * @throws {Error} If transition is invalid
 */
export function validateTransition(fromPhase, toPhase) {
  if (!fromPhase) {
    throw new Error('Current phase is undefined. Cannot validate transition.');
  }

  if (!toPhase) {
    throw new Error('Target phase is undefined. Cannot validate transition.');
  }

  if (!isValidTransition(fromPhase, toPhase)) {
    const validPhases = getValidNextPhases(fromPhase);
    const fromDisplay = getPhaseDisplayName(fromPhase);
    const toDisplay = getPhaseDisplayName(toPhase);

    throw new Error(
      `Invalid phase transition: ${fromDisplay} → ${toDisplay}\n\n` +
      `Valid next phases from ${fromDisplay}:\n` +
      validPhases.map(p => `  • ${getPhaseDisplayName(p)}`).join('\n') +
      '\n\n' +
      'You cannot skip phases in the MORPH workflow.\n' +
      'To override this check, use the --force flag (not recommended).'
    );
  }
}

/**
 * Get the sequential order of phases
 * @returns {string[]} Ordered list of phases
 */
export function getPhaseSequence() {
  return [
    'proposal',
    'setup',
    'uiux',     // optional
    'design',
    'clarify',
    'tasks',
    'implement',
    'sync',     // optional
    'archived'
  ];
}

/**
 * Get phase order index (for comparison)
 * @param {string} phase - Phase identifier
 * @returns {number} Index in sequence (-1 if not found)
 */
export function getPhaseOrder(phase) {
  return getPhaseSequence().indexOf(phase);
}

/**
 * Check if target phase is ahead of current phase
 * @param {string} currentPhase - Current phase
 * @param {string} targetPhase - Target phase
 * @returns {boolean} True if target is ahead
 */
export function isPhaseAhead(currentPhase, targetPhase) {
  return getPhaseOrder(targetPhase) > getPhaseOrder(currentPhase);
}

/**
 * Check if target phase is behind current phase (rollback scenario)
 * @param {string} currentPhase - Current phase
 * @param {string} targetPhase - Target phase
 * @returns {boolean} True if target is behind
 */
export function isPhaseRollback(currentPhase, targetPhase) {
  return getPhaseOrder(targetPhase) < getPhaseOrder(currentPhase);
}

/**
 * Get all skipped phases between two phases
 * @param {string} fromPhase - Starting phase
 * @param {string} toPhase - Ending phase
 * @returns {string[]} Array of skipped phases
 */
export function getSkippedPhases(fromPhase, toPhase) {
  const sequence = getPhaseSequence();
  const fromIndex = sequence.indexOf(fromPhase);
  const toIndex = sequence.indexOf(toPhase);

  if (fromIndex === -1 || toIndex === -1 || toIndex <= fromIndex) {
    return [];
  }

  return sequence.slice(fromIndex + 1, toIndex);
}

/**
 * Validate that no required phases were skipped
 * @param {string} fromPhase - Starting phase
 * @param {string} toPhase - Ending phase
 * @throws {Error} If required phases were skipped
 */
export function validateNoRequiredPhasesSkipped(fromPhase, toPhase) {
  const skipped = getSkippedPhases(fromPhase, toPhase);
  const requiredSkipped = skipped.filter(p => !isOptionalPhase(p));

  if (requiredSkipped.length > 0) {
    throw new Error(
      `Cannot skip required phases:\n` +
      requiredSkipped.map(p => `  • ${getPhaseDisplayName(p)}`).join('\n') +
      '\n\nYou must complete each required phase in sequence.'
    );
  }
}

/**
 * Get comprehensive phase information
 * @param {string} phase - Phase identifier
 * @returns {Object} Phase metadata
 */
export function getPhaseInfo(phase) {
  return {
    id: phase,
    displayName: getPhaseDisplayName(phase),
    order: getPhaseOrder(phase),
    isOptional: isOptionalPhase(phase),
    validNextPhases: getValidNextPhases(phase),
    canTransitionTo: (targetPhase) => isValidTransition(phase, targetPhase)
  };
}
