use chrono::{DateTime, Utc};
use crate::types::NormalizedEntity;
use crate::ir::TemporalStrategy;

#[derive(Debug, PartialEq)]
pub enum TemporalResult {
    Valid,
    Historical,
    NoOverlap,
}

pub struct TemporalMatcher;

impl TemporalMatcher {
    pub fn evaluate(
        strategy: &TemporalStrategy,
        a: &NormalizedEntity,
        b: &NormalizedEntity,
        as_of: Option<DateTime<Utc>>,
    ) -> (TemporalResult, f64) {
        let as_of = as_of.unwrap_or_else(Utc::now);

        match strategy {
            TemporalStrategy::LatestOnly => {
                if Self::is_historical(a, as_of) || Self::is_historical(b, as_of) {
                    return (TemporalResult::Historical, 0.0);
                }
                (TemporalResult::Valid, 1.0)
            },
            TemporalStrategy::PointInTime => {
                let valid_a = Self::is_valid_at(a, as_of);
                let valid_b = Self::is_valid_at(b, as_of);

                if valid_a && valid_b {
                    (TemporalResult::Valid, 1.0)
                } else {
                    (TemporalResult::Historical, 0.0)
                }
            },
            TemporalStrategy::BiTemporal => {
                if Self::ranges_overlap(a, b) {
                    (TemporalResult::Valid, 1.0)
                } else {
                    (TemporalResult::NoOverlap, 0.0)
                }
            }
        }
    }

    fn is_historical(e: &NormalizedEntity, as_of: DateTime<Utc>) -> bool {
        if let Some(to) = e.valid_to {
            return to < as_of;
        }
        false
    }

    fn is_valid_at(e: &NormalizedEntity, t: DateTime<Utc>) -> bool {
        let from_ok = e.valid_from.map(|f| f <= t).unwrap_or(true);
        let to_ok = e.valid_to.map(|to| to >= t).unwrap_or(true);
        from_ok && to_ok
    }

    fn ranges_overlap(a: &NormalizedEntity, b: &NormalizedEntity) -> bool {
        let a_start = a.valid_from.unwrap_or(DateTime::<Utc>::MIN_UTC);
        let a_end = a.valid_to.unwrap_or(DateTime::<Utc>::MAX_UTC);
        
        let b_start = b.valid_from.unwrap_or(DateTime::<Utc>::MIN_UTC);
        let b_end = b.valid_to.unwrap_or(DateTime::<Utc>::MAX_UTC);

        a_start <= b_end && b_start <= a_end
    }
}
