namespace Theriapolis.Core.Rules.Combat;

/// <summary>
/// Per-attack situation modifiers. Flags compose: a Sneak Attack with
/// Advantage and Disadvantage (e.g. attacker prone, target shadowed)
/// cancels to a normal roll per d20 rules.
///
/// Phase 5 M4 wires the basic six (Advantage/Disadvantage and the four
/// resolver-time tags); class-feature flags like Reckless Attack come in
/// M6 once the feature engine reads from this enum.
/// </summary>
[System.Flags]
public enum SituationFlags : uint
{
    None              = 0,
    Advantage         = 1u << 0,
    Disadvantage      = 1u << 1,
    /// <summary>Attacker is at long range — disadvantage on the roll per d20.</summary>
    LongRange         = 1u << 2,
    /// <summary>Attacker has reach + a melee weapon vs. a target that has cover.</summary>
    HalfCover         = 1u << 3,
    ThreeQuartersCover= 1u << 4,
    /// <summary>Attacker meets the Sneak Attack precondition (advantage or ally adjacent).</summary>
    SneakAttackEligible = 1u << 5,
    /// <summary>Attacker is firing a ranged weapon at a target within 5 ft. — disadvantage.</summary>
    RangedInMelee     = 1u << 6,
}

public static class SituationFlagsExtensions
{
    /// <summary>
    /// True when the situation should roll the d20 with advantage. Per
    /// d20 rules, advantage and disadvantage cancel exactly (no doubling).
    /// </summary>
    public static bool RollsAdvantage(this SituationFlags f)
    {
        bool adv = (f & SituationFlags.Advantage) != 0;
        bool dis = (f & SituationFlags.Disadvantage) != 0
                || (f & SituationFlags.LongRange) != 0
                || (f & SituationFlags.RangedInMelee) != 0;
        return adv && !dis;
    }

    /// <summary>True when the situation rolls with disadvantage (and no compensating advantage).</summary>
    public static bool RollsDisadvantage(this SituationFlags f)
    {
        bool adv = (f & SituationFlags.Advantage) != 0;
        bool dis = (f & SituationFlags.Disadvantage) != 0
                || (f & SituationFlags.LongRange) != 0
                || (f & SituationFlags.RangedInMelee) != 0;
        return dis && !adv;
    }

    /// <summary>Cover modifier applied to AC: 0 / 2 / 5.</summary>
    public static int CoverAcBonus(this SituationFlags f)
    {
        if ((f & SituationFlags.ThreeQuartersCover) != 0) return 5;
        if ((f & SituationFlags.HalfCover)          != 0) return 2;
        return 0;
    }
}
