using System.Collections.Frozen;

namespace NeonSprawl.Server.Game.Crafting;

/// <summary>
/// Prototype Slice 3 roster gate (NEO-65), mirrored from <c>scripts/validate_content.py</c>
/// <c>PROTOTYPE_SLICE3_RECIPE_IDS</c> / <c>_prototype_slice3_recipe_gate</c>.
/// </summary>
public static class PrototypeSlice3RecipeCatalogRules
{
    /// <summary>Keep in sync with <c>scripts/validate_content.py</c> <c>PROTOTYPE_SLICE3_RECIPE_IDS</c>.</summary>
    public static readonly FrozenSet<string> ExpectedRecipeIds = FrozenSet.ToFrozenSet(
        [
            "refine_scrap_standard",
            "refine_scrap_efficient",
            "make_field_stim_mk0",
            "make_field_stim_batch",
            "make_prototype_armor",
            "make_armor_quick",
            "make_survey_drone_kit",
            "make_contract_token",
        ],
        StringComparer.Ordinal);

    /// <summary>Keep in sync with <c>scripts/validate_content.py</c> <c>PROTOTYPE_SLICE3_REFINE_SKILL_ID</c>.</summary>
    public const string ExpectedRefineSkillId = "refine";

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

        var kinds = idToRecipeKind.Values.ToHashSet(StringComparer.Ordinal);
        if (!kinds.Contains("process") || !kinds.Contains("make"))
        {
            return
                "error: prototype Slice 3 requires at least one process and one make recipe; " +
                $"recipeKind values seen: [{string.Join(", ", kinds.Order(StringComparer.Ordinal).Select(k => "'" + k + "'"))}]";
        }

        foreach (var (rid, skillId) in idToRequiredSkillId)
        {
            if (skillId != ExpectedRefineSkillId)
            {
                return
                    $"error: '{rid}' requiredSkillId must be '{ExpectedRefineSkillId}', got '{skillId}'";
            }
        }

        return null;
    }
}
