using System.Collections;
using System.Collections.Generic;
using Cute;
using LitJson;
using UnityEngine;
using Wizard.Scripts.Network.Data.TaskData.SpotCardExchange;

namespace SVSimLoader.Patches;

/// <summary>
/// Fires GachaPointExchangeInfoTask (pack/get_gacha_point_rewards) for every
/// parent_gacha_id in /pack/info's pack_config_list, on the first /pack/info response
/// of the session. Responses are captured by the existing traffic hook in
/// ExaminationPatches.SetResponseData — no extra writer needed.
///
/// Originally targeted pack/get_leader_skin_owned_status (Plan B in the leader-cards
/// design doc), but that endpoint is server-gated on an active skin-select offering
/// and returned result_code=205 across all 35 packs in the May 2026 catalog. Switched
/// to pack/get_gacha_point_rewards which exposes the same card_id → leader_skin_id
/// mapping (via reward_type=10 entries) without the gate, and additionally yields
/// emblem/sleeve associations for every tradeable card.
///
/// Gated by SvSimConfig.SweepLeaderSkinPools (off by default).
/// Hits a prod API — keep pacing conservative.
/// </summary>
internal static class LeaderSkinPoolSweep
{
    private static bool _sweepStarted;
    private static readonly object _lock = new object();

    public static void OnPackInfoResponse(JsonData data)
    {
        lock (_lock)
        {
            if (_sweepStarted) return;
            _sweepStarted = true;
        }

        var ids = ExtractParentGachaIds(data);
        if (ids.Count == 0)
        {
            Plugin.Log.LogWarning("LeaderSkinPoolSweep: /pack/info had no pack_config_list — nothing to sweep.");
            return;
        }
        if (Plugin.Instance == null)
        {
            Plugin.Log.LogError("LeaderSkinPoolSweep: Plugin.Instance is null — cannot start coroutine.");
            return;
        }
        Plugin.Log.LogInfo($"LeaderSkinPoolSweep: queued {ids.Count} packs for /pack/get_gacha_point_rewards sweep.");
        Plugin.Instance.StartCoroutine(SweepCoroutine(ids));
    }

    private static List<int> ExtractParentGachaIds(JsonData data)
    {
        var ids = new List<int>();
        if (data == null || !data.IsObject)
        {
            Plugin.Log.LogWarning("LeaderSkinPoolSweep: /pack/info response data was null or non-object.");
            return ids;
        }

        // Defensive: the data parameter to SetResponseData might be either the inner `data`
        // payload (matching the DumpUserData assumption) or the full envelope with data_headers
        // outside. Different endpoints in this codebase seem to differ; check both shapes.
        JsonData list = null;
        if (data.Keys.Contains("pack_config_list"))
        {
            list = data["pack_config_list"];
        }
        else if (data.Keys.Contains("data") && data["data"] != null && data["data"].IsObject
                 && data["data"].Keys.Contains("pack_config_list"))
        {
            list = data["data"]["pack_config_list"];
        }

        if (list == null)
        {
            var keys = string.Join(", ", data.Keys);
            Plugin.Log.LogWarning($"LeaderSkinPoolSweep: pack_config_list not found at either data.pack_config_list or data.data.pack_config_list. Top-level keys observed: [{keys}]");
            return ids;
        }
        if (!list.IsArray)
        {
            Plugin.Log.LogWarning($"LeaderSkinPoolSweep: pack_config_list was found but is not an array (type tag mismatch).");
            return ids;
        }

        for (int i = 0; i < list.Count; i++)
        {
            var item = list[i];
            if (item == null || !item.IsObject || !item.Keys.Contains("parent_gacha_id")) continue;
            var v = item["parent_gacha_id"];
            if (v.IsInt) ids.Add((int)v);
            else if (v.IsLong) ids.Add((int)(long)v);
        }
        return ids;
    }

    private static IEnumerator SweepCoroutine(List<int> parentGachaIds)
    {
        int ok = 0, fail = 0;
        for (int i = 0; i < parentGachaIds.Count; i++)
        {
            int id = parentGachaIds[i];
            // odds_gacha_id and parent_gacha_id observed equal in the natural-flow capture
            // (data_dumps/traffic_prod_tradeables_capture.ndjson). Pass the same value twice.
            GachaPointExchangeInfoTask task = new GachaPointExchangeInfoTask();
            task.SetParameter(id, id);
            Plugin.Log.LogInfo($"LeaderSkinPoolSweep: [{i + 1}/{parentGachaIds.Count}] parent_gacha_id={id}");
            yield return Toolbox.NetworkManager.Connect(task, _ => { });
            if (task.isServerResultCodeOK())
            {
                ok++;
            }
            else
            {
                fail++;
                Plugin.Log.LogWarning($"LeaderSkinPoolSweep: parent_gacha_id={id} returned result_code={task.GetResultCode()}");
            }
            // 0.5s per request is conservative pacing for a prod API. 35 packs ≈ 18s total.
            yield return new WaitForSeconds(0.5f);
        }
        Plugin.Log.LogInfo($"LeaderSkinPoolSweep: complete. ok={ok} fail={fail}/{parentGachaIds.Count}");
    }
}
