using System.Collections.Frozen;

namespace NeonSprawl.Server.Game.Skills;

/// <summary>
/// Prototype Slice 1 roster gate (NEO-33), mirrored from <c>scripts/validate_content.py</c>
/// <c>PROTOTYPE_SLICE1_SKILL_IDS</c> / <c>_prototype_slice1_gate</c>.
/// </summary>
public static class PrototypeSlice1SkillCatalogRules
{
    /// <summary>Keep in sync with <c>scripts/validate_content.py</c> <c>PROTOTYPE_SLICE1_SKILL_IDS</c>.</summary>
    public static readonly FrozenSet<string> ExpectedSkillIds = FrozenSet.ToFrozenSet(
        ["salvage", "refine", "intrusion"],
        StringComparer.Ordinal);

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

        var cats = skillIdToCategory.Values.ToHashSet(StringComparer.Ordinal);
        if (!cats.Contains("gather") || !cats.Contains("tech"))
        {
            return
                "error: prototype Slice 1 requires at least one gather and one tech skill; " +
                $"categories seen: [{string.Join(", ", cats.Order(StringComparer.Ordinal).Select(c => "'" + c + "'"))}]";
        }

        if (!cats.Contains("process") && !cats.Contains("make"))
        {
            return
                "error: prototype Slice 1 requires at least one process or make skill; " +
                $"categories seen: [{string.Join(", ", cats.Order(StringComparer.Ordinal).Select(c => "'" + c + "'"))}]";
        }

        return null;
    }
}
