using System.Text.Json;
using System.Text.Json.Serialization;
using Prospect.Server.Api.Models.Data;
using Prospect.Server.Api.Services.Auth.Extensions;
using Prospect.Server.Api.Services.CloudScript;
using Prospect.Server.Api.Services.UserData;

public class FYFortunaPassClaimedRewards {
    [JsonPropertyName("rewardsIds")]
	public List<string> RewardsIDs { get; set; }
};

// Récompense d'un palier de la passe (catalogue optionnel TitleData "FortunaPass2_Rewards").
// itemId "SoftCurrency"/"Aurum"/"InsuranceCurrency" = monnaie, sinon item d'inventaire.
public class FortunaPassRewardDef {
    [JsonPropertyName("itemId")]
    public string ItemId { get; set; }
    [JsonPropertyName("amount")]
    public int Amount { get; set; }
}

public class RequestClaimFortunaPassRewardsRequest
{
    [JsonPropertyName("rewardsIds")]
    public string[] RewardsIDs { get; set; }
}

public class RequestClaimFortunaPassRewardsResponse
{
    [JsonPropertyName("userIds")]
    public string UserId { get; set; }
    [JsonPropertyName("error")]
	public string Error { get; set; }
    [JsonPropertyName("errorType")]
	public int ErrorType { get; set; }
    [JsonPropertyName("grantedItems")]
	public FYCustomItemInfo[] GrantedItems { get; set; }
    [JsonPropertyName("changedCurrencies")]
	public FYCurrencyItem[] ChangedCurrencies { get; set; }
}

[CloudScriptFunction("RequestClaimFortunaPassRewards")]
public class RequestClaimFortunaPassRewardsFunction : ICloudScriptFunction<RequestClaimFortunaPassRewardsRequest, RequestClaimFortunaPassRewardsResponse>
{
    private readonly IHttpContextAccessor _httpContextAccessor;
    private readonly UserDataService _userDataService;
    private readonly TitleDataService _titleDataService;
    private readonly ILogger<RequestClaimFortunaPassRewardsFunction> _logger;

    public RequestClaimFortunaPassRewardsFunction(IHttpContextAccessor httpContextAccessor, UserDataService userDataService, TitleDataService titleDataService, ILogger<RequestClaimFortunaPassRewardsFunction> logger)
    {
        _httpContextAccessor = httpContextAccessor;
        _userDataService = userDataService;
        _titleDataService = titleDataService;
        _logger = logger;
    }

    public async Task<RequestClaimFortunaPassRewardsResponse> ExecuteAsync(RequestClaimFortunaPassRewardsRequest request)
    {
        var context = _httpContextAccessor.HttpContext;
        if (context == null)
        {
            throw new CloudScriptException("CloudScript was not called within a http request");
        }
        var userId = context.User.FindAuthUserId();

        // Clé de la saison courante (déterminée par la config de build) — évite d'écraser
        // la progression de l'autre saison (l'ancien code écrasait S2 ET S3).
#if SEASON_3_RELEASE || SEASON_3_DEBUG
        const string claimedKey = "FortunaPass3_ClaimedRewards";
        const string rewardsCatalogKey = "FortunaPass3_Rewards";
#else
        const string claimedKey = "FortunaPass2_ClaimedRewards";
        const string rewardsCatalogKey = "FortunaPass2_Rewards";
#endif

        var userData = await _userDataService.FindAsync(userId, userId, new List<string>{ claimedKey, "Inventory", "Balance" });
        var claimedRewards = JsonSerializer.Deserialize<FYFortunaPassClaimedRewards>(userData[claimedKey].Value)
            ?? new FYFortunaPassClaimedRewards { RewardsIDs = new List<string>() };
        claimedRewards.RewardsIDs ??= new List<string>();

        // Catalogue des récompenses (optionnel) : rewardId -> {itemId, amount}.
        Dictionary<string, FortunaPassRewardDef> catalog = null;
        try
        {
            var td = _titleDataService.Find(new List<string> { rewardsCatalogKey });
            if (td.TryGetValue(rewardsCatalogKey, out var raw) && !string.IsNullOrWhiteSpace(raw))
                catalog = JsonSerializer.Deserialize<Dictionary<string, FortunaPassRewardDef>>(raw);
        }
        catch { /* pas de catalogue → on enregistre seulement la réclamation */ }

        var inventory = JsonSerializer.Deserialize<List<FYCustomItemInfo>>(userData["Inventory"].Value) ?? new List<FYCustomItemInfo>();
        var balance = JsonSerializer.Deserialize<PlayerBalance>(userData["Balance"].Value);
        var grantedItems = new List<FYCustomItemInfo>();
        var changedCurrencies = new List<FYCurrencyItem>();

        foreach (var rewardId in request.RewardsIDs)
        {
            // Ne pas re-créditer un palier déjà réclamé.
            if (claimedRewards.RewardsIDs.Contains(rewardId)) continue;

            if (catalog == null || !catalog.TryGetValue(rewardId, out var def) || def == null)
            {
                // Le catalogue des paliers est défini côté client (DataTable). On journalise
                // les IDs inconnus pour pouvoir construire un vrai catalogue FortunaPass{2,3}_Rewards
                // qui matche. IMPORTANT : ne PAS marquer le palier comme réclamé si on ne peut rien
                // accorder — sinon il serait brûlé définitivement et inclaimable une fois le
                // catalogue ajouté.
                _logger.LogInformation("FortunaPass claim: aucun catalogue pour le reward '{RewardId}' (catalogue {State}) — non accordé", rewardId, catalog == null ? "absent" : "présent");
                continue;
            }

            claimedRewards.RewardsIDs.Add(rewardId);
            _logger.LogInformation("FortunaPass claim: octroi reward '{RewardId}' -> {ItemId} x{Amount}", rewardId, def.ItemId, def.Amount);

            switch (def.ItemId)
            {
                case "SoftCurrency":
                    balance.SoftCurrency += def.Amount;
                    changedCurrencies.Add(new FYCurrencyItem { CurrencyName = "SoftCurrency", Amount = balance.SoftCurrency });
                    break;
                case "Aurum":
                    balance.HardCurrency += def.Amount;
                    changedCurrencies.Add(new FYCurrencyItem { CurrencyName = "Aurum", Amount = balance.HardCurrency });
                    break;
                case "InsuranceCurrency":
                    balance.InsuranceCurrency += def.Amount;
                    changedCurrencies.Add(new FYCurrencyItem { CurrencyName = "InsuranceCurrency", Amount = balance.InsuranceCurrency });
                    break;
                default:
                    var item = new FYCustomItemInfo {
                        ItemId = Guid.NewGuid().ToString(),
                        Amount = def.Amount <= 0 ? 1 : def.Amount,
                        BaseItemId = def.ItemId,
                        Durability = 0,
                        Insurance = "",
                        InsuranceOwnerPlayfabId = "",
                        ModData = new FYModItems { M = [] },
                        Origin = new FYItemOriginBackend { G = "", P = "", T = "" },
                        InsuredAttachmentId = "",
                        PrimaryVanityId = 0,
                        SecondaryVanityId = 0,
                        RolledPerks = [],
                    };
                    inventory.Add(item);
                    grantedItems.Add(item);
                    break;
            }
        }

        var changes = new Dictionary<string, string> { [claimedKey] = JsonSerializer.Serialize(claimedRewards) };
        if (grantedItems.Count > 0) changes["Inventory"] = JsonSerializer.Serialize(inventory);
        if (changedCurrencies.Count > 0) changes["Balance"] = JsonSerializer.Serialize(balance);
        await _userDataService.UpdateAsync(userId, userId, changes);

        return new RequestClaimFortunaPassRewardsResponse
        {
            UserId = userId,
            ErrorType = 3, // EYFortunaPassToastReponseType::Ok
            Error = "",
            GrantedItems = grantedItems.ToArray(),
            ChangedCurrencies = changedCurrencies.ToArray(),
        };
    }
}
