use maat_sdk::predicate::{EntityRef, EntitySet, Op, PoolMode, Predicate, Value};
use maat_sdk::PoolId;
use maat_sdk_derive::gate;

#[test]
fn pool_compare_self() {
    let hp = PoolId::new("test:hp", "HP");
    let p = gate!(pool!(SELF, hp) >= 10);
    let expected = Predicate::Cmp(
        Value::Pool {
            entity: EntityRef::Self_,
            key: hp.clone(),
            mode: PoolMode::Base,
        },
        Op::Ge,
        Value::Const(10),
    );
    assert_eq!(p, expected);
}

#[test]
fn type_eq_with_it() {
    use maat_sdk::EntityTypeId;
    let wizard = EntityTypeId::from_raw(5101);
    let p = gate!(type_eq(IT, wizard));
    let expected = Predicate::Cmp(
        Value::TypeOf(EntityRef::It),
        Op::Eq,
        Value::ConstType(wizard),
    );
    assert_eq!(p, expected);
}

#[test]
fn any_attached_with_where_clause() {
    use maat_sdk::EntityTypeId;
    let level = PoolId::new("dnd5e:level", "Level");
    let wizard = EntityTypeId::from_raw(5101);
    let p = gate!(any_attached(SELF) where {
        type_eq(IT, wizard) && pool!(IT, level) >= 2
    });
    let expected = Predicate::AnyOf(
        EntitySet::AttachedTo(EntityRef::Self_),
        Box::new(Predicate::All(vec![
            Predicate::Cmp(
                Value::TypeOf(EntityRef::It),
                Op::Eq,
                Value::ConstType(wizard),
            ),
            Predicate::Cmp(
                Value::Pool {
                    entity: EntityRef::It,
                    key: level.clone(),
                    mode: PoolMode::Base,
                },
                Op::Ge,
                Value::Const(2),
            ),
        ])),
    );
    assert_eq!(p, expected);
}

#[test]
fn boolean_composition() {
    let hp = PoolId::new("test:hp", "HP");
    let p = gate!(pool!(SELF, hp) >= 10 && pool!(SELF, hp) <= 100);
    if let Predicate::All(inner) = p {
        assert_eq!(inner.len(), 2);
    } else {
        panic!("expected All");
    }
}

#[test]
fn negation() {
    let p = gate!(!exists(TARGET));
    let expected = Predicate::Not(Box::new(Predicate::Exists(EntityRef::Target)));
    assert_eq!(p, expected);
}

#[test]
fn pool_eff_uses_effective_mode() {
    let str_key = PoolId::new("dnd5e:str", "STR");
    let p = gate!(pool_eff!(SELF, str_key) >= 13);
    let expected = Predicate::Cmp(
        Value::Pool {
            entity: EntityRef::Self_,
            key: str_key.clone(),
            mode: PoolMode::Effective,
        },
        Op::Ge,
        Value::Const(13),
    );
    assert_eq!(p, expected);
}
