//! Developmental phase controller.
//!
//! Drives the worm through four developmental phases:
//!
//! 1. **Genesis** — High plasticity, permissive wiring, no disc activation.
//!    Neurons scatter, form random connections, explore space.
//!
//! 2. **Exposure** — Body stimuli drive activity, disc pressure accumulates.
//!    Neurons begin correlating with external signals.
//!
//! 3. **Differentiation** — Disc programs fire, nuclei shift, roles emerge.
//!    Neurons physically change to become sensory/motor/hub.
//!
//! 4. **Crystallization** — Plasticity drops, structure locks in.
//!    The worm is now a worm.

/// The four developmental phases.
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub enum DevelopmentalPhase {
    Genesis,
    Exposure,
    Differentiation,
    Crystallization,
}

impl DevelopmentalPhase {
    /// Human-readable name.
    pub fn name(self) -> &'static str {
        match self {
            Self::Genesis => "genesis",
            Self::Exposure => "exposure",
            Self::Differentiation => "differentiation",
            Self::Crystallization => "crystallization",
        }
    }
}

/// Configuration for phase durations.
#[derive(Clone, Debug)]
pub struct PhaseConfig {
    /// Frames in genesis phase.
    pub genesis_frames: u64,
    /// Frames in exposure phase.
    pub exposure_frames: u64,
    /// Frames in differentiation phase.
    pub differentiation_frames: u64,
    /// Frames in crystallization phase (after this, sim is "mature").
    pub crystallization_frames: u64,
}

impl Default for PhaseConfig {
    fn default() -> Self {
        Self {
            genesis_frames: 500,
            exposure_frames: 2000,
            differentiation_frames: 1000,
            crystallization_frames: 1000,
        }
    }
}

impl PhaseConfig {
    /// Total frames across all phases.
    pub fn total_frames(&self) -> u64 {
        self.genesis_frames
            + self.exposure_frames
            + self.differentiation_frames
            + self.crystallization_frames
    }
}

/// Tracks developmental progress through the four phases.
#[derive(Clone, Debug)]
pub struct PhaseController {
    pub current_phase: DevelopmentalPhase,
    /// Frames spent in the current phase.
    pub phase_frame: u64,
    /// Total frames across all phases.
    pub total_frame: u64,
    config: PhaseConfig,
}

impl PhaseController {
    pub fn new(config: PhaseConfig) -> Self {
        Self {
            current_phase: DevelopmentalPhase::Genesis,
            phase_frame: 0,
            total_frame: 0,
            config,
        }
    }

    /// Advance one frame. Returns true if a phase transition occurred.
    pub fn advance(&mut self) -> bool {
        self.phase_frame += 1;
        self.total_frame += 1;

        let limit = match self.current_phase {
            DevelopmentalPhase::Genesis => self.config.genesis_frames,
            DevelopmentalPhase::Exposure => self.config.exposure_frames,
            DevelopmentalPhase::Differentiation => self.config.differentiation_frames,
            DevelopmentalPhase::Crystallization => self.config.crystallization_frames,
        };

        if self.phase_frame >= limit {
            let next = match self.current_phase {
                DevelopmentalPhase::Genesis => Some(DevelopmentalPhase::Exposure),
                DevelopmentalPhase::Exposure => Some(DevelopmentalPhase::Differentiation),
                DevelopmentalPhase::Differentiation => Some(DevelopmentalPhase::Crystallization),
                DevelopmentalPhase::Crystallization => None, // terminal
            };

            if let Some(next_phase) = next {
                self.current_phase = next_phase;
                self.phase_frame = 0;
                return true;
            }
        }

        false
    }

    /// Is development complete (past all phases)?
    pub fn is_mature(&self) -> bool {
        self.current_phase == DevelopmentalPhase::Crystallization
            && self.phase_frame >= self.config.crystallization_frames
    }

    /// Progress through current phase (0.0–1.0).
    pub fn phase_progress(&self) -> f32 {
        let limit = match self.current_phase {
            DevelopmentalPhase::Genesis => self.config.genesis_frames,
            DevelopmentalPhase::Exposure => self.config.exposure_frames,
            DevelopmentalPhase::Differentiation => self.config.differentiation_frames,
            DevelopmentalPhase::Crystallization => self.config.crystallization_frames,
        };
        if limit == 0 { return 1.0; }
        (self.phase_frame as f32 / limit as f32).min(1.0)
    }

    /// Overall developmental progress (0.0–1.0).
    pub fn overall_progress(&self) -> f32 {
        let total = self.config.total_frames();
        if total == 0 { return 1.0; }
        (self.total_frame as f32 / total as f32).min(1.0)
    }

    /// Migration rate multiplier for the current phase.
    pub fn migration_rate(&self) -> f32 {
        match self.current_phase {
            DevelopmentalPhase::Genesis => 2.0,          // high migration
            DevelopmentalPhase::Exposure => 1.0,         // normal
            DevelopmentalPhase::Differentiation => 0.5,  // slowing down
            DevelopmentalPhase::Crystallization => 0.1,  // locked in
        }
    }

    /// Plasticity multiplier for the current phase.
    pub fn plasticity_rate(&self) -> f32 {
        match self.current_phase {
            DevelopmentalPhase::Genesis => 1.5,          // high plasticity
            DevelopmentalPhase::Exposure => 1.0,         // normal
            DevelopmentalPhase::Differentiation => 1.2,  // elevated for re-wiring
            DevelopmentalPhase::Crystallization => 0.2,  // mostly frozen
        }
    }

    /// Wiring radius multiplier for the current phase.
    pub fn wiring_radius(&self) -> f32 {
        match self.current_phase {
            DevelopmentalPhase::Genesis => 2.0,          // permissive
            DevelopmentalPhase::Exposure => 1.0,         // normal
            DevelopmentalPhase::Differentiation => 1.5,  // allow re-wiring
            DevelopmentalPhase::Crystallization => 0.5,  // tight
        }
    }

    /// Should disc programs accumulate pressure this phase?
    pub fn discs_accumulate(&self) -> bool {
        matches!(
            self.current_phase,
            DevelopmentalPhase::Exposure | DevelopmentalPhase::Differentiation
        )
    }

    /// Should disc programs trigger differentiation this phase?
    pub fn discs_differentiate(&self) -> bool {
        self.current_phase == DevelopmentalPhase::Differentiation
    }

    /// Should mastery learning be active this phase?
    pub fn mastery_active(&self) -> bool {
        !matches!(self.current_phase, DevelopmentalPhase::Genesis)
    }

    /// Access the phase config.
    pub fn config(&self) -> &PhaseConfig {
        &self.config
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn phase_progression() {
        let config = PhaseConfig {
            genesis_frames: 10,
            exposure_frames: 10,
            differentiation_frames: 10,
            crystallization_frames: 10,
        };
        let mut ctrl = PhaseController::new(config);

        assert_eq!(ctrl.current_phase, DevelopmentalPhase::Genesis);

        // Run through genesis
        for _ in 0..9 {
            assert!(!ctrl.advance());
        }
        assert!(ctrl.advance()); // transition at frame 10
        assert_eq!(ctrl.current_phase, DevelopmentalPhase::Exposure);

        // Run through exposure
        for _ in 0..9 { ctrl.advance(); }
        assert!(ctrl.advance());
        assert_eq!(ctrl.current_phase, DevelopmentalPhase::Differentiation);

        // Run through differentiation
        for _ in 0..9 { ctrl.advance(); }
        assert!(ctrl.advance());
        assert_eq!(ctrl.current_phase, DevelopmentalPhase::Crystallization);

        // Crystallization doesn't transition further
        for _ in 0..9 { ctrl.advance(); }
        assert!(!ctrl.advance()); // stays in crystallization
        assert!(ctrl.is_mature());
    }

    #[test]
    fn phase_progress_tracking() {
        let config = PhaseConfig {
            genesis_frames: 100,
            exposure_frames: 100,
            differentiation_frames: 100,
            crystallization_frames: 100,
        };
        let mut ctrl = PhaseController::new(config);

        for _ in 0..50 {
            ctrl.advance();
        }

        assert!((ctrl.phase_progress() - 0.5).abs() < 0.02);
        assert!((ctrl.overall_progress() - 0.125).abs() < 0.02);
    }

    #[test]
    fn phase_multipliers() {
        let ctrl = PhaseController::new(PhaseConfig::default());

        // Genesis has high migration and wiring
        assert!(ctrl.migration_rate() > 1.0);
        assert!(ctrl.wiring_radius() > 1.0);
        assert!(!ctrl.mastery_active());
        assert!(!ctrl.discs_accumulate());
    }
}
