//! Phase 29ao P0: CorePlan composer scaffold (CanonicalLoopFacts -> CorePlan)

use super::{CorePlan, DomainPlan, Pattern1SimpleWhilePlan};
use crate::mir::builder::control_flow::plan::facts::skeleton_facts::SkeletonKind;
use crate::mir::builder::control_flow::plan::normalize::CanonicalLoopFacts;
use crate::mir::builder::control_flow::plan::planner::Freeze;

#[allow(dead_code)]
pub(in crate::mir::builder) fn try_compose_domain_plan_from_canonical_facts(
    facts: &CanonicalLoopFacts,
) -> Result<Option<DomainPlan>, Freeze> {
    if !matches!(facts.skeleton_kind, SkeletonKind::Loop) {
        return Ok(None);
    }
    let Some(pattern1) = &facts.facts.pattern1_simplewhile else {
        return Ok(None);
    };
    Ok(Some(DomainPlan::Pattern1SimpleWhile(
        Pattern1SimpleWhilePlan {
            loop_var: pattern1.loop_var.clone(),
            condition: pattern1.condition.clone(),
            loop_increment: pattern1.loop_increment.clone(),
        },
    )))
}

#[allow(dead_code)]
pub(in crate::mir::builder) fn try_compose_core_plan_from_canonical_facts(
    facts: &CanonicalLoopFacts,
) -> Result<Option<CorePlan>, Freeze> {
    debug_assert!(
        matches!(facts.skeleton_kind, SkeletonKind::Loop),
        "composer expects Loop skeleton facts only"
    );
    Ok(None)
}

#[cfg(test)]
mod tests {
    use super::{
        try_compose_core_plan_from_canonical_facts, try_compose_domain_plan_from_canonical_facts,
    };
    use crate::ast::{ASTNode, BinaryOperator, LiteralValue, Span};
    use crate::mir::builder::control_flow::plan::facts::feature_facts::LoopFeatureFacts;
    use crate::mir::builder::control_flow::plan::facts::loop_facts::LoopFacts;
    use crate::mir::builder::control_flow::plan::facts::pattern1_simplewhile_facts::Pattern1SimpleWhileFacts;
    use crate::mir::builder::control_flow::plan::facts::scan_shapes::{
        ConditionShape, StepShape,
    };
    use crate::mir::builder::control_flow::plan::facts::skeleton_facts::{
        SkeletonFacts, SkeletonKind,
    };
    use crate::mir::builder::control_flow::plan::normalize::canonicalize_loop_facts;
    use crate::mir::builder::control_flow::plan::DomainPlan;

    fn v(name: &str) -> ASTNode {
        ASTNode::Variable {
            name: name.to_string(),
            span: Span::unknown(),
        }
    }

    fn lit_int(value: i64) -> ASTNode {
        ASTNode::Literal {
            value: LiteralValue::Integer(value),
            span: Span::unknown(),
        }
    }

    #[test]
    fn composer_scaffold_returns_none() {
        let facts = LoopFacts {
            condition_shape: ConditionShape::Unknown,
            step_shape: StepShape::Unknown,
            skeleton: SkeletonFacts {
                kind: SkeletonKind::Loop,
            },
            features: LoopFeatureFacts::default(),
            scan_with_init: None,
            split_scan: None,
            pattern1_simplewhile: None,
            pattern3_ifphi: None,
            pattern4_continue: None,
            pattern5_infinite_early_exit: None,
            pattern8_bool_predicate_scan: None,
            pattern9_accum_const_loop: None,
            pattern2_break: None,
            pattern2_loopbodylocal: None,
        };
        let canonical = canonicalize_loop_facts(facts);
        let composed =
            try_compose_core_plan_from_canonical_facts(&canonical).expect("Ok");
        assert!(composed.is_none());
    }

    #[test]
    fn composer_bridge_builds_pattern1_domain_plan() {
        let pattern1 = Pattern1SimpleWhileFacts {
            loop_var: "i".to_string(),
            condition: ASTNode::BinaryOp {
                operator: BinaryOperator::Less,
                left: Box::new(v("i")),
                right: Box::new(lit_int(3)),
                span: Span::unknown(),
            },
            loop_increment: ASTNode::BinaryOp {
                operator: BinaryOperator::Add,
                left: Box::new(v("i")),
                right: Box::new(lit_int(1)),
                span: Span::unknown(),
            },
        };
        let facts = LoopFacts {
            condition_shape: ConditionShape::Unknown,
            step_shape: StepShape::Unknown,
            skeleton: SkeletonFacts {
                kind: SkeletonKind::Loop,
            },
            features: LoopFeatureFacts::default(),
            scan_with_init: None,
            split_scan: None,
            pattern1_simplewhile: Some(pattern1),
            pattern3_ifphi: None,
            pattern4_continue: None,
            pattern5_infinite_early_exit: None,
            pattern8_bool_predicate_scan: None,
            pattern9_accum_const_loop: None,
            pattern2_break: None,
            pattern2_loopbodylocal: None,
        };
        let canonical = canonicalize_loop_facts(facts);
        let plan =
            try_compose_domain_plan_from_canonical_facts(&canonical).expect("Ok");
        assert!(matches!(
            plan,
            Some(DomainPlan::Pattern1SimpleWhile(_))
        ));
    }

    #[test]
    fn composer_bridge_returns_none_without_pattern1() {
        let facts = LoopFacts {
            condition_shape: ConditionShape::Unknown,
            step_shape: StepShape::Unknown,
            skeleton: SkeletonFacts {
                kind: SkeletonKind::Loop,
            },
            features: LoopFeatureFacts::default(),
            scan_with_init: None,
            split_scan: None,
            pattern1_simplewhile: None,
            pattern3_ifphi: None,
            pattern4_continue: None,
            pattern5_infinite_early_exit: None,
            pattern8_bool_predicate_scan: None,
            pattern9_accum_const_loop: None,
            pattern2_break: None,
            pattern2_loopbodylocal: None,
        };
        let canonical = canonicalize_loop_facts(facts);
        let plan =
            try_compose_domain_plan_from_canonical_facts(&canonical).expect("Ok");
        assert!(plan.is_none());
    }
}
