use llmenv::config::{Config, Scopes};
use llmenv::scope::Env;
use proptest::prelude::*;

// ===== Scope Evaluation Determinism =====

#[test]
fn prop_scope_evaluation_is_deterministic() {
    proptest!(|(hostname in "[a-z0-9]{1,20}")| {
            let cfg = Config {
                scope: Scopes {
                    host: vec![
                        llmenv::config::HostScope {
                            id: "h1".into(),
                            r#match: llmenv::config::HostMatch {
                                hostname: Some(hostname.clone()),
                            },
                            tags: vec!["tag1".into()],
    },
                        llmenv::config::HostScope {
                            id: "h2".into(),
                            r#match: llmenv::config::HostMatch {
                                hostname: None,
                            },
                            tags: vec!["tag2".into()],
    },
                    ],
                    ..Default::default()
                },
                ..Default::default()
            };

            let env = Env {
                hostname: hostname.clone(),
                user: "testuser".into(),
                cwd: "/tmp".into(),
                ..Env::empty()
            };

            let result1 = llmenv::scope::evaluate(&cfg, &env);
            let result2 = llmenv::scope::evaluate(&cfg, &env);

            assert_eq!(result1.scopes.len(), result2.scopes.len());
            assert_eq!(result1.tags.len(), result2.tags.len());

            for (s1, s2) in result1.scopes.iter().zip(result2.scopes.iter()) {
                assert_eq!(s1.id, s2.id);
                assert_eq!(s1.tags, s2.tags);
            }
        });
}

// ===== Multiple Scope Matches Accumulate Tags =====

#[test]
fn prop_multiple_scopes_accumulate_tags() {
    proptest!(|(
            hostname in "[a-z0-9]{1,15}",
            user in "[a-z]{1,10}"
        )| {
            let cfg = Config {
                scope: Scopes {
                    host: vec![llmenv::config::HostScope {
                        id: "h".into(),
                        r#match: llmenv::config::HostMatch {
                            hostname: Some(hostname.clone()),
                        },
                        tags: vec!["host_tag".into()],
    }],
                    user: vec![llmenv::config::UserScope {
                        id: "u".into(),
                        r#match: llmenv::config::UserMatch {
                            user: Some(user.clone()),
                        },
                        tags: vec!["user_tag".into()],
    }],
                    ..Default::default()
                },
                ..Default::default()
            };

            let env = Env {
                hostname: hostname.clone(),
                user: user.clone(),
                cwd: "/tmp".into(),
                ..Env::empty()
            };

            let active = llmenv::scope::evaluate(&cfg, &env);

            assert_eq!(active.scopes.len(), 2);
            assert!(active.tags.contains("host_tag"));
            assert!(active.tags.contains("user_tag"));
        });
}

// ===== Scope Order Independence =====

#[test]
fn prop_scope_matching_order_independent() {
    proptest!(|(hostname in "[a-z0-9]{1,15}")| {
            let scope1 = llmenv::config::HostScope {
                id: "first".into(),
                r#match: llmenv::config::HostMatch {
                    hostname: Some(hostname.clone()),
                },
                tags: vec!["tag1".into()],
    };

            let scope2 = llmenv::config::HostScope {
                id: "second".into(),
                r#match: llmenv::config::HostMatch {
                    hostname: None,
                },
                tags: vec!["tag2".into()],
    };

            let cfg1 = Config {
                scope: Scopes {
                    host: vec![scope1.clone(), scope2.clone()],
                    ..Default::default()
                },
                ..Default::default()
            };

            let cfg2 = Config {
                scope: Scopes {
                    host: vec![scope2.clone(), scope1.clone()],
                    ..Default::default()
                },
                ..Default::default()
            };

            let env = Env {
                hostname: hostname.clone(),
                user: "testuser".into(),
                cwd: "/tmp".into(),
                ..Env::empty()
            };

            let result1 = llmenv::scope::evaluate(&cfg1, &env);
            let result2 = llmenv::scope::evaluate(&cfg2, &env);

            let ids1: std::collections::HashSet<_> =
                result1.scopes.iter().map(|s| s.id.as_str()).collect();
            let ids2: std::collections::HashSet<_> =
                result2.scopes.iter().map(|s| s.id.as_str()).collect();

            assert_eq!(ids1, ids2);
        });
}
