//! UC-08 F6 — `GmScope` enum BDD scenarios.
//!
//! Spec: `docs/superpowers/specs/2026-05-23-UC08-F6-adjudication-scoping.md`.
//!
//! Scenarios:
//! - F6-1: `GmScope::All` covers any seat / any pool.
//! - F6-2: `GmScope::Seats(set)` covers only listed seats and no pools.
//! - F6-3: `GmScope::Pools(set)` covers only listed pools and no seats.
//! - F6-4: Default `GmScope` is `All`.

use std::collections::HashSet;

use maat_sdk_types::config::{GmScope, SessionConfig};
use maat_sdk_types::types::{PoolId, SeatId};

#[test]
fn f6_1_all_covers_any_seat_and_any_pool() {
    let scope = GmScope::All;
    let pool = PoolId::new("dnd5e:hp", "HP");
    assert!(scope.covers_seat(Some(SeatId::from_raw(0))));
    assert!(scope.covers_seat(Some(SeatId::from_raw(42))));
    assert!(scope.covers_seat(None));
    assert!(scope.covers_pool(Some(&pool)));
    assert!(scope.covers_pool(None));
}

#[test]
fn f6_2_seats_covers_only_listed_seats_and_no_pools() {
    let s0 = SeatId::from_raw(0);
    let s1 = SeatId::from_raw(1);
    let s9 = SeatId::from_raw(9);
    let mut allowed = HashSet::new();
    allowed.insert(s0);
    allowed.insert(s1);
    let scope = GmScope::Seats(allowed);

    // Listed seats covered.
    assert!(scope.covers_seat(Some(s0)));
    assert!(scope.covers_seat(Some(s1)));
    // Unlisted seat not covered.
    assert!(!scope.covers_seat(Some(s9)));
    // No-seat suspension not covered (don't have a way to attribute it).
    assert!(!scope.covers_seat(None));

    // Pool scope is disjoint from seat scope — Seats variant never
    // covers pools, regardless of pool argument.
    let pool = PoolId::new("dnd5e:hp", "HP");
    assert!(!scope.covers_pool(Some(&pool)));
    assert!(!scope.covers_pool(None));
}

#[test]
fn f6_3_pools_covers_only_listed_pools_and_no_seats() {
    let hp    = PoolId::new("dnd5e:hp", "HP");
    let mana  = PoolId::new("dnd5e:mana", "Mana");
    let gold  = PoolId::new("game:gold", "Gold");
    let mut allowed = HashSet::new();
    allowed.insert(hp.clone());
    allowed.insert(mana.clone());
    let scope = GmScope::Pools(allowed);

    assert!(scope.covers_pool(Some(&hp)));
    assert!(scope.covers_pool(Some(&mana)));
    assert!(!scope.covers_pool(Some(&gold)));
    assert!(!scope.covers_pool(None));

    // Seat scope disjoint from pool scope.
    assert!(!scope.covers_seat(Some(SeatId::from_raw(0))));
    assert!(!scope.covers_seat(None));
}

#[test]
fn f6_4_default_gm_scope_is_all() {
    let scope: GmScope = GmScope::default();
    assert!(matches!(scope, GmScope::All));

    // SessionConfig.gm_scope defaults to an empty map; absent entries
    // get treated as `GmScope::All` by the routing code path.
    let cfg = SessionConfig::new(0, 0);
    assert!(cfg.gm_scope.is_empty());
}
