using NeonSprawl.Server.Game.Items;
using NeonSprawl.Server.Game.Mastery;
using NeonSprawl.Server.Game.PositionState;
using NeonSprawl.Server.Game.Skills;

namespace NeonSprawl.Server.Game.Crafting;

/// <summary>Maps <c>POST /game/players/{{id}}/craft</c> — craft execution (NEO-70).</summary>
public static class PlayerCraftApi
{
    public static WebApplication MapPlayerCraftApi(this WebApplication app)
    {
        app.MapPost(
            "/game/players/{id}/craft",
            (string id, PlayerCraftRequest? body, IPositionStateStore positions,
                IRecipeDefinitionRegistry recipeRegistry, IItemDefinitionRegistry itemRegistry,
                IPlayerInventoryStore inventoryStore, ISkillDefinitionRegistry skillRegistry,
                IPlayerSkillProgressionStore xpStore, ISkillLevelCurve levelCurve,
                PerkUnlockEngine perkUnlockEngine) =>
            {
                if (body is null || body.SchemaVersion != PlayerCraftRequest.CurrentSchemaVersion)
                {
                    return Results.BadRequest();
                }

                if (body.RecipeId is null || body.RecipeId.Trim().Length == 0)
                {
                    return Results.BadRequest();
                }

                var trimmedId = id.Trim();
                if (trimmedId.Length == 0 || !positions.TryGetPosition(trimmedId, out _))
                {
                    return Results.NotFound();
                }

                var quantity = body.Quantity ?? 1;
                var result = CraftOperations.TryCraft(
                    trimmedId,
                    body.RecipeId,
                    quantity,
                    recipeRegistry,
                    itemRegistry,
                    inventoryStore,
                    skillRegistry,
                    xpStore,
                    levelCurve,
                    perkUnlockEngine);

                if (!result.Success &&
                    (string.Equals(result.ReasonCode, CraftReasonCodes.InventoryStoreMissing, StringComparison.Ordinal) ||
                     string.Equals(result.ReasonCode, CraftReasonCodes.ProgressionStoreMissing, StringComparison.Ordinal)))
                {
                    return Results.NotFound();
                }

                return Results.Json(MapResponse(result));
            });

        return app;
    }

    internal static CraftResponse MapResponse(CraftResult result)
    {
        CraftXpGrantSummaryJson? xp = null;
        if (result.XpGrantSummary is { } summary)
        {
            xp = new CraftXpGrantSummaryJson
            {
                SkillId = summary.SkillId,
                Amount = summary.Amount,
                SourceKind = summary.SourceKind,
            };
        }

        return new CraftResponse
        {
            Success = result.Success,
            ReasonCode = result.ReasonCode,
            InputsConsumed = MapIoRows(result.InputsConsumed),
            OutputsGranted = MapIoRows(result.OutputsGranted),
            XpGrantSummary = xp,
        };
    }

    private static IReadOnlyList<CraftIoAppliedJson> MapIoRows(IReadOnlyList<CraftIoApplied> rows)
    {
        if (rows.Count == 0)
        {
            return Array.Empty<CraftIoAppliedJson>();
        }

        var mapped = new CraftIoAppliedJson[rows.Count];
        for (var i = 0; i < rows.Count; i++)
        {
            var row = rows[i];
            mapped[i] = new CraftIoAppliedJson
            {
                ItemId = row.ItemId,
                Quantity = row.Quantity,
            };
        }

        return mapped;
    }
}
