pub mod validation;
pub mod engine;

// Re-export public API (same paths as before for consumers)
pub use engine::types;
pub use engine::normalization;
pub use engine::matching;
pub use engine::blocking;
pub use engine::survivorship;
pub use engine::temporal;
pub use engine::overrides;
pub use engine::compiler;
pub use engine::compiler as spec_compiler;
pub use engine::observability;

#[cfg(feature = "server")]
mod metrics_wrapper {
    use crate::engine;
    use crate::types::{NormalizedEntity, MatchDecision};
    use crate::overrides::OverrideResolver;
    use cannon_common::ir::IdentityPlan;
    use uuid::Uuid;
    use metrics::{counter, histogram};
    use tracing::{instrument, info};

    pub struct ReconciliationEngine {
        inner: engine::ReconciliationEngine,
    }

    impl ReconciliationEngine {
        pub fn new(
            rules: Vec<Box<dyn engine::matching::MatchRule>>,
            blocking_strategies: Vec<Box<dyn engine::blocking::BlockingStrategy>>,
            merge_threshold: f64,
            review_threshold: f64,
        ) -> Self {
            Self {
                inner: engine::ReconciliationEngine::new(
                    rules,
                    blocking_strategies,
                    merge_threshold,
                    review_threshold,
                )
            }
        }

        pub fn from_plan(plan: &IdentityPlan) -> Self {
            Self {
                inner: engine::ReconciliationEngine::from_plan(plan)
            }
        }

        #[instrument(skip(self, entities, override_resolver), fields(entity_count = entities.len()))]
        pub fn reconcile(&self, entities: &[NormalizedEntity], override_resolver: &OverrideResolver) -> Vec<MatchDecision> {
            let start = std::time::Instant::now();
            info!("Starting reconciliation for {} entities", entities.len());

            let final_decisions = self.inner.reconcile(entities, override_resolver);

            let duration = start.elapsed();
            histogram!("reconcile_duration_seconds", duration.as_secs_f64());
            for decision in &final_decisions {
                counter!("match_decisions_total", 1, "decision" => format!("{:?}", decision.decision));
            }
            info!("Reconciliation complete in {:?}. Found {} decisions", duration, final_decisions.len());

            final_decisions
        }

        #[instrument(skip(self, entities, override_resolver), fields(entity_count = entities.len()))]
        pub fn reconcile_with_telemetry(&self, entities: &[NormalizedEntity], override_resolver: &OverrideResolver) -> (Vec<MatchDecision>, super::observability::ReconciliationTelemetry) {
            let start = std::time::Instant::now();
            info!("Starting reconciliation with telemetry for {} entities", entities.len());

            let (decisions, telemetry) = self.inner.reconcile_with_telemetry(entities, override_resolver);

            let duration = start.elapsed();
            histogram!("reconcile_duration_seconds", duration.as_secs_f64());
            info!("Reconciliation with telemetry complete in {:?}. Found {} decisions, {} pairs evaluated",
                duration, decisions.len(), telemetry.pairs_evaluated);

            (decisions, telemetry)
        }

        pub fn cluster_decisions(&self, entities: &[NormalizedEntity], decisions: &[MatchDecision]) -> Vec<Vec<Uuid>> {
            self.inner.cluster_decisions(entities, decisions)
        }

        #[instrument(skip(self, a, b, resolver), fields(id_a = ?a.id, id_b = ?b.id))]
        pub fn evaluate_pair(&self, a: &NormalizedEntity, b: &NormalizedEntity, resolver: &OverrideResolver, scale: f64) -> MatchDecision {
            let decision = self.inner.evaluate_pair(a, b, resolver, scale);
            counter!("match_decisions_total", 1, "decision" => format!("{:?}", decision.decision));
            decision
        }

        #[instrument(skip(self, clusters, entities, resolver, initial_decisions), fields(cluster_count = clusters.len()))]
        pub fn propagate_relations(
            &self,
            clusters: &[Vec<Uuid>],
            entities: &[NormalizedEntity],
            resolver: &OverrideResolver,
            initial_decisions: &[MatchDecision],
        ) -> Vec<MatchDecision> {
            self.inner.propagate_relations(clusters, entities, resolver, initial_decisions)
        }
    }
}

#[cfg(feature = "server")]
pub use metrics_wrapper::ReconciliationEngine;
