//! FIFA 17 economy POLICY mappers (pure, game-specific).
//!
//! These translate FIFA 17 wire semantics into the generic amounts the host
//! feeds to Core economy authority. They own NO state — Core owns balances and
//! inventory; these are the FIFA-specific numbers/derivations. Values are the
//! current OpenFUT economy (match rewards are the Python oracle's
//! `MATCH_COINS`/`MATCH_PARTICIPATION` at production defaults); pack prices come
//! from the Store catalogue.

use crate::fut::store_catalog::pack_by_id;

/// Normalized match outcome for reward purposes.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MatchResult {
    Win,
    Draw,
    Loss,
}

/// Participation award added to every match reward (oracle `MATCH_PARTICIPATION`
/// default = 0).
pub const MATCH_PARTICIPATION: i64 = 0;

/// Per-result match coins (oracle `MATCH_COINS`: won 400 / draw 200 / loss 100).
pub fn match_result_coins(result: MatchResult) -> i64 {
    match result {
        MatchResult::Win => 400,
        MatchResult::Draw => 200,
        MatchResult::Loss => 100,
    }
}

/// Total match reward = per-result coins + participation.
pub fn match_reward_total(result: MatchResult) -> i64 {
    match_result_coins(result) + MATCH_PARTICIPATION
}

/// Derive the outcome from the match `endReason` enum (the oracle's primary
/// signal, `_END_REASON`). Unknown/absent reasons default to `Draw`, matching
/// the oracle's conservative default. Score-based derivation is a fallback the
/// oracle also supports; the enum is authoritative when present.
pub fn result_from_end_reason(end_reason: Option<&str>) -> MatchResult {
    match end_reason.unwrap_or("").to_ascii_uppercase().as_str() {
        "WIN" | "DNF_WIN" => MatchResult::Win,
        "LOSS" | "QUIT" | "DNF" | "DNF_LOSS" => MatchResult::Loss,
        // "DRAW", "DNF_DRAW", "NO_CONTEST", unknown -> draw.
        _ => MatchResult::Draw,
    }
}

/// The Store buy-now price for a pack id (`None` for unknown/owned-only packs,
/// which are never purchasable).
pub fn pack_price(pack_id: u64) -> Option<u64> {
    pack_by_id(pack_id)
        .filter(|p| !p.owned_only)
        .map(|p| p.price)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn match_rewards_match_oracle() {
        assert_eq!(match_reward_total(MatchResult::Win), 400);
        assert_eq!(match_reward_total(MatchResult::Draw), 200);
        assert_eq!(match_reward_total(MatchResult::Loss), 100);
    }

    #[test]
    fn end_reason_maps_to_outcome() {
        assert_eq!(result_from_end_reason(Some("WIN")), MatchResult::Win);
        assert_eq!(result_from_end_reason(Some("dnf_win")), MatchResult::Win);
        assert_eq!(result_from_end_reason(Some("LOSS")), MatchResult::Loss);
        assert_eq!(result_from_end_reason(Some("QUIT")), MatchResult::Loss);
        assert_eq!(result_from_end_reason(Some("DRAW")), MatchResult::Draw);
        assert_eq!(result_from_end_reason(None), MatchResult::Draw);
        assert_eq!(result_from_end_reason(Some("weird")), MatchResult::Draw);
    }

    #[test]
    fn pack_price_rejects_unknown_and_owned_only() {
        assert!(pack_price(1).is_some());
        assert_eq!(pack_price(65534), None); // sentinel absent from catalogue
        assert_eq!(pack_price(70), None); // owned-only reward pack, not purchasable
    }
}
