using System.Collections.Frozen;

namespace NeonSprawl.Server.Game.Npc;

/// <summary>
/// Prototype E5M2 roster + numeric gates (NEO-87 / NEO-88), mirrored from <c>scripts/validate_content.py</c>
/// <c>PROTOTYPE_E5M2_NPC_BEHAVIOR_IDS</c>, <c>_prototype_e5m2_npc_behavior_gate</c>, and
/// <c>_prototype_e5m2_npc_behavior_numeric_gate</c>.
/// </summary>
public static class PrototypeE5M2NpcBehaviorCatalogRules
{
    /// <summary>Keep in sync with <c>scripts/validate_content.py</c> <c>PROTOTYPE_E5M2_NPC_BEHAVIOR_IDS</c>.</summary>
    public static readonly FrozenSet<string> ExpectedBehaviorIds = FrozenSet.ToFrozenSet(
        [
            "prototype_melee_pressure",
            "prototype_ranged_control",
            "prototype_elite_mini_boss",
        ],
        StringComparer.Ordinal);

    /// <summary>Returns a human-readable error if the E5M2 behavior contract fails, otherwise <see langword="null"/>.</summary>
    public static string? TryGetE5M2GateError(IReadOnlyDictionary<string, string> behaviorIdToSourceFile)
    {
        var ids = behaviorIdToSourceFile.Keys.ToFrozenSet(StringComparer.Ordinal);
        if (!ids.SetEquals(ExpectedBehaviorIds))
        {
            return
                "error: prototype E5M2 expects exactly npc behavior ids " +
                $"[{string.Join(", ", ExpectedBehaviorIds.Order(StringComparer.Ordinal).Select(s => "'" + s + "'"))}], " +
                $"got [{string.Join(", ", ids.Order(StringComparer.Ordinal).Select(s => "'" + s + "'"))}]";
        }

        return null;
    }

    /// <summary>Returns a human-readable error when <c>leashRadius &lt;= aggroRadius</c>, otherwise <see langword="null"/>.</summary>
    public static string? TryGetNumericGateError(IReadOnlyDictionary<string, NpcBehaviorDefRow> rowsById)
    {
        foreach (var (bid, row) in rowsById)
        {
            if (row.LeashRadius <= row.AggroRadius)
            {
                return
                    $"error: npc behavior '{bid}': leashRadius {row.LeashRadius} must be > aggroRadius {row.AggroRadius}";
            }
        }

        return null;
    }
}
