using System.Reflection;
using System.Reflection.Metadata;
using System.Text.RegularExpressions;
using Titled_Gui.Data.Game;

namespace Titled_Gui.Classes
{
    internal class OffsetGetter
    {
        private static readonly Dictionary<string, int> offsets = []; // holds the resolved offsets
        private static readonly HttpClient httpClient = new();
        private static string _offsetRegex = @"public const nint ([\w\+]+) = (0x[0-9A-Fa-f]+);";

        static OffsetGetter()
        {
            try
            {
                httpClient.Timeout = TimeSpan.FromSeconds(10);
                httpClient.DefaultRequestHeaders.UserAgent.ParseAdd("Mozilla/5.0 (Windows NT 10.0; Win64; x64)");
            }
            catch (Exception e)
            {
                Console.WriteLine($"[偏移查找] 错误: {e.Message}");
            }
        }
        // urls to pull the dumper outputs from
        private const string OffsetsUrl = "https://raw.githubusercontent.com/xfi0/cs2-dumper/main/output/offsets.cs";
        private const string SecondaryOffsetsUrl = "https://raw.githubusercontent.com/sezzyaep/CS2-OFFSETS/refs/heads/main/offsets.cs";
        private const string ClientDllUrl = "https://raw.githubusercontent.com/xfi0/cs2-dumper/main/output/client_dll.cs";
        private const string SecondaryClientDllUrl = "https://raw.githubusercontent.com/sezzyaep/CS2-OFFSETS/refs/heads/main/client_dll.cs";
        private const string ButtonsUrl = "https://raw.githubusercontent.com/xfi0/cs2-dumper/main/output/buttons.cs";
        private const string SecondaryButtonsUrl = "https://raw.githubusercontent.com/sezzyaep/CS2-OFFSETS/refs/heads/main/buttons.cs";
        private const string Engine2Url = "https://raw.githubusercontent.com/xfi0/cs2-dumper/main/output/engine2_dll.cs";
        private const string SecondaryEngine2Url = "https://raw.githubusercontent.com/sezzyaep/CS2-OFFSETS/refs/heads/main/engine2_dll.cs";
        private const string AnimationSystemUrl = "https://raw.githubusercontent.com/xfi0/cs2-dumper/main/output/animationsystem_dll.cs";
        private const string SecondaryAnimationSystemUrl = "https://raw.githubusercontent.com/sezzyaep/CS2-OFFSETS/refs/heads/main/animationsystem_dll.cs";

        private static string OffsetsContent = string.Empty;
        private static string ClientDllContent = string.Empty;
        private static string ButtonsContent = string.Empty;
        private static string Engine2Content = string.Empty;
        private static string AnimationSystemContent = string.Empty;

        public static bool Updated = false;

        private class Offset(string name, string? className = null)
        {
            public string Name { get; } = name;
            public string? ClassName { get; } = className;
        }


        private static readonly Dictionary<string, List<Offset>> FieldNameMappings = new()
        {
            { "dwViewMatrix", new() { new Offset("dwViewMatrix") } },
            { "dwEntityList", new() { new Offset("dwEntityList") } },
            { "dwLocalPlayerPawn", new() { new Offset("dwLocalPlayerPawn") } },
            { "dwLocalPlayerController", new() { new Offset("dwLocalPlayerController") } },
            { "dwViewAngles", new() { new Offset("dwViewAngles") } },
            { "dwGlobalVars", new() { new Offset("dwGlobalVars") } },
            { "dwPlantedC4", new() { new Offset("dwPlantedC4") } },
            { "dwGameRules", new() { new Offset("dwGameRules") } },
            { "dwSensitivity", new() { new Offset("dwSensitivity") } },
            { "dwSensitivity_sensitivity", new() { new Offset("dwSensitivity_sensitivity") } },
            { "dwCSGOInput", new() { new Offset("dwCSGOInput") } },
            { "attack", new() { new Offset("attack"), new Offset("+attack") } },
            { "jump", new() { new Offset("jump"), new Offset("+jump") } },
            { "m_pCameraServices", new() { new Offset("m_pCameraServices"), new Offset("m_CameraServices") } },
            { "m_iFOV", new() { new Offset("m_iFOV"), new Offset("m_iDesiredFOV") } },
            { "m_bIsScoped", new() { new Offset("m_bIsScoped"), new Offset("m_bIsScopedIn") } },
            { "m_iHealth", new() { new Offset("m_iHealth") } },
            { "m_bSpotted", new() { new Offset("m_bSpotted"), new Offset("m_bSpottedBy") } },
            { "m_iIDEntIndex", new() { new Offset("m_iIDEntIndex") } },
            { "m_pSceneNode", new() { new Offset("m_pSceneNode"), new Offset("m_pRenderingNode") } },
            { "m_vecViewOffset", new() { new Offset("m_vecViewOffset"), new Offset("m_vViewOffset") } },
            { "m_lifeState", new() { new Offset("m_lifeState") } },
            { "m_vOldOrigin", new() { new Offset("m_vOldOrigin") } },
            { "m_iTeamNum", new() { new Offset("m_iTeamNum") } },
            { "m_hPlayerPawn", new() { new Offset("m_hPlayerPawn") } },
            { "m_flFlashScreenshotAlpha", new() { new Offset("m_flFlashScreenshotAlpha"), new Offset("m_flFlashDuration") } },
            { "m_flFlashBangTime", new() { new Offset("m_flFlashBangTime"), new Offset("m_flFlashDuration") } },
            { "m_modelState", new() { new Offset("m_modelState") } },
            { "m_pGameSceneNode", new() { new Offset("m_pGameSceneNode") } },
            { "m_flC4Blow", new() { new Offset("m_flC4Blow"), new Offset("m_flDetonateTime") } },
            { "current_time", new() { new Offset("current_time"), new Offset("m_flCurrentTime") } },
            { "m_bBombPlanted", new() { new Offset("m_bBombPlanted"), new Offset("m_bBombTicking") } },
            { "m_pClippingWeapon", new() { new Offset("m_pClippingWeapon") } },
            { "m_iItemDefinitionIndex", new() { new Offset("m_iItemDefinitionIndex") } },
            { "m_bSpottedByMask", new() { new Offset("m_bSpottedByMask") } },
            { "m_pWeaponServices", new() { new Offset("m_pWeaponServices") } },
            { "m_hActiveWeapon", new() { new Offset("m_hActiveWeapon") } },
            { "m_vecAbsVelocity", new() { new Offset("m_vecAbsVelocity") } },
            { "m_fFlags", new() { new Offset("m_fFlags") } },
            { "m_hMyWeapons", new() { new Offset("m_hMyWeapons") } },
            { "m_aimPunchAngle", new() { new Offset("m_aimPunchAngle") } },
            { "m_nCurrentTickThisFrame", new() { new Offset("m_nCurrentTickThisFrame") } },
            { "m_ArmorValue", new() { new Offset("m_ArmorValue") } },
            { "m_pInGameMoneyServices", new() { new Offset("m_pInGameMoneyServices") } },
            { "m_iAccount", new() { new Offset("m_iAccount") } },
            { "m_iTotalCashSpent", new() { new Offset("m_iTotalCashSpent") } },
            { "m_iCashSpentThisRound", new() { new Offset("m_iCashSpentThisRound") } },
            { "m_bIsDefusing", new() { new Offset("m_bIsDefusing") } },
            { "m_bInBombZone", new() { new Offset("m_bInBombZone") } },
            { "m_bIsBuyMenuOpen", new() { new Offset("m_bIsBuyMenuOpen") } },
            { "m_aimPunchCache", new() { new Offset("m_aimPunchCache") } },
            { "m_iAmmo", new() { new Offset("m_iAmmo") } },
            { "m_iPing", new() { new Offset("m_iPing") } },
            { "m_bIsWalking", new() { new Offset("m_bIsWalking") } },
            { "m_totalHitsOnServer", new() { new Offset("m_totalHitsOnServer") } },
            { "m_angEyeAngles", new() { new Offset("m_angEyeAngles") } },
            { "m_iSpectatorSlotCount", new() { new Offset("m_iSpectatorSlotCount") } },
            { "m_iShotsFired", new() { new Offset("m_iShotsFired") } },
            { "m_vecAbsOrigin", new() { new Offset("m_vecAbsOrigin") } },
            { "m_GunGameImmunityColor", new() { new Offset("m_GunGameImmunityColor") } },
            { "m_flEmitSoundTime", new() { new Offset("m_flEmitSoundTime") } },
            { "m_vecMins", new() { new Offset("m_vecMins") } },
            { "m_vMinBounds", new() { new Offset("m_vMinBounds") } },
            { "m_vMaxBounds", new() { new Offset("m_vMaxBounds") } },
            { "m_flShapeRadius", new() { new Offset("m_flShapeRadius") } },
            { "m_sBoneName", new() { new Offset("m_sBoneName") } },
            { "m_name", new() { new Offset("m_name") } },
            { "m_nShapeType", new() { new Offset("m_nShapeType") } },
            { "m_sSurfaceProperty", new() { new Offset("m_sSurfaceProperty") } },
            { "m_vecMaxs", new() { new Offset("m_vecMaxs") } },
            { "v_angle", new() { new Offset("v_angle") } },
            { "m_Collision", new() { new Offset("m_Collision") } },
            { "m_CHitboxComponent", new() { new Offset("m_CHitboxComponent") } },
            { "m_bDormant", new() { new Offset("m_bDormant") } },
            { "m_nSmokeEffectTickBegin", new() { new Offset("m_nSmokeEffectTickBegin") } },
            { "m_pEntity", new() { new Offset("m_pEntity") } },
            { "m_designerName", new() { new Offset("m_designerName") } },
            { "m_bSmokeEffectSpawned", new() { new Offset("m_bSmokeEffectSpawned") } },
            { "m_bSmokeVolumeDataReceived", new() { new Offset("m_bSmokeVolumeDataReceived") } },
            { "m_nVoxelUpdate", new() { new Offset("m_nVoxelUpdate") } },
            { "m_hOwnerEntity", new() { new Offset("m_hOwnerEntity") } },
            { "m_nodeToWorld", new() { new Offset("m_nodeToWorld") } },
            { "m_nBombSite", new() { new Offset("m_nBombSite") } },
            { "m_bBeingDefused", new() { new Offset("m_bBeingDefused") } },
            { "m_bC4Activated", new() { new Offset("m_bC4Activated") } },
            { "m_pObserverServices", new() { new Offset("m_pObserverServices") } },
            { "m_hObserverTarget", new() { new Offset("m_hObserverTarget") } },
            { "m_hPawn", new() { new Offset("m_hPawn") } },
            { "m_szCustomName", new() { new Offset("m_szCustomName") } },
            { "m_pAimPunchServices", new() { new Offset("m_pAimPunchServices") } },
            { "m_predictableBaseAngle", new() { new Offset("m_predictableBaseAngle") } },
            { "m_predictableBaseAngleVel", new() { new Offset("m_predictableBaseAngleVel") } },
            { "m_hInfernoPointsSnapshot", new() { new Offset("m_hInfernoPointsSnapshot") } },
            { "m_hInfernoFillerPointsSnapshot", new() { new Offset("m_hInfernoFillerPointsSnapshot") } },
            { "m_hInfernoDecalsSnapshot", new() { new Offset("m_hInfernoDecalsSnapshot") } },
            { "m_firePositions", new() { new Offset("m_firePositions") } },
            { "m_fireCount", new() { new Offset("m_fireCount") } },


            // EXPLICIT CLASS THING
            { "m_pActionTrackingServices", new() { new Offset("m_pActionTrackingServices", "CCSPlayerController") } },
            { "m_pBulletServices", new() { new Offset("m_pBulletServices", "CCSPlayerController") } },
            { "m_flTotalRoundDamageDealt", new() { new Offset("m_flTotalRoundDamageDealt", "CCSPlayerController") } },
            { "m_iNumRoundKills", new() { new Offset("m_iNumRoundKills", "CCSPlayerController_ActionTrackingServices") } },
            { "m_iNumRoundKillsHeadshots", new() { new Offset("m_iNumRoundKillsHeadshots", "CCSPlayerController_ActionTrackingServices") } },
            { "m_entitySpottedState", new() { new Offset("m_entitySpottedState", "C_CSPlayerPawn") } },
            { "m_vecOrigin", new() { new Offset("m_vecOrigin", "CGameSceneNode") } },
            { "m_angRotation", new() { new Offset("m_angRotation", "CGameSceneNode") } },
            { "m_vSmokeColor", new() { new Offset("m_vSmokeColor", "C_SmokeGrenadeProjectile") } },
            { "m_vSmokeDetonationPos", new() { new Offset("m_vSmokeDetonationPos", "C_SmokeGrenadeProjectile") } },
            { "m_VoxelFrameData", new() { new Offset("m_VoxelFrameData", "C_SmokeGrenadeProjectile") } },
            { "m_nVoxelFrameDataSize", new() { new Offset("m_nVoxelFrameDataSize", "C_SmokeGrenadeProjectile") } },
            { "m_nRandomSeed", new() { new Offset("m_nRandomSeed", "C_SmokeGrenadeProjectile") } },
            { "m_bDidSmokeEffect", new() { new Offset("m_bDidSmokeEffect", "C_SmokeGrenadeProjectile") } },
            { "m_nInButtonsWhichAreToggles", new() { new Offset("m_nInButtonsWhichAreToggles", "C_SmokeGrenadeProjectile") } },
            { "m_CommandContext", new() { new Offset("m_CommandContext", "C_SmokeGrenadeProjectile") } },
            { "m_iszPlayerName", new() { new Offset("m_iszPlayerName", "CBasePlayerController") } },
            { "m_AttributeManager", new() { new Offset("m_AttributeManager", "C_EconEntity") } },
            { "m_Item", new() { new Offset("m_Item", "C_AttributeContainer") } },
            { "m_ModelName", new() { new Offset("m_ModelName", "CModelState") } },
            //{ "m_bBombPlanted", new() { new Offset("m_bBombPlanted", "C_CSGameRules") } },

        };

        public static async Task UpdateOffsetsAsync()
        {
            try
            {
                Console.WriteLine("[偏移查找] 正在开始查找偏移，请稍候...");
                offsets.Clear();

                // download and cache
                OffsetsContent = await DownloadFile(OffsetsUrl);
                ClientDllContent = await DownloadFile(ClientDllUrl);
                ButtonsContent = await DownloadFile(ButtonsUrl);
                Engine2Content = await DownloadFile(Engine2Url);
                AnimationSystemContent = await DownloadFile(AnimationSystemUrl);

                ParseOffsetsFile(OffsetsContent);
                ParseClientDllFile(ClientDllContent);
                ParseButtonsFile(ButtonsContent);
                ParseEngine2File(Engine2Content);
                ParseAnimationSystemFile(AnimationSystemContent);

                Console.WriteLine($"[偏移查找] 已找到: {offsets.Count}");
                UpdateOffsetsClass();

                Console.WriteLine("[偏移查找] 偏移更新成功！");
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[偏移查找] 错误: {ex.Message}");
            }
        }

        public static async Task CheckIfOffsetsAreValid()
        {
            if (GameState.memory == null)
                return;

            if (GameState.CS2Open() && (GameState.memory.ReadPointer(GameState.client, Offsets.dwViewMatrix) == IntPtr.Zero || GameState.memory.ReadPointer(GameState.client, Offsets.dwEntityList) == IntPtr.Zero))
            {
                Console.WriteLine("[偏移查找] 主数据源尚未更新，正在尝试备用数据源");
                offsets.Clear();
                await FetchSecondarySource();

                ParseOffsetsFile(OffsetsContent);
                ParseClientDllFile(ClientDllContent);
                ParseButtonsFile(ButtonsContent);
                ParseEngine2File(Engine2Content);
                ParseAnimationSystemFile(AnimationSystemContent);
                UpdateOffsetsClass();

                if (GameState.memory.ReadPointer(GameState.client, Offsets.dwViewMatrix) == IntPtr.Zero || GameState.memory.ReadPointer(GameState.client, Offsets.dwEntityList) == IntPtr.Zero)
                {
                    Console.WriteLine("两个数据源均无效，也许可以尝试自行导出？");
                    Updated = true;
                    return;
                }

                Updated = true;
                return;
            }
            else
            {
                Updated = true;
            }
        }

        public static void ApplySecondarySources()
        {
            if (Updated)
                return;

            ParseOffsetsFile(OffsetsContent);
            ParseClientDllFile(ClientDllContent);
            ParseButtonsFile(ButtonsContent);
            ParseEngine2File(Engine2Content);
            ParseAnimationSystemFile(AnimationSystemContent);
            UpdateOffsetsClass();
        }

        public static async Task FetchSecondarySource()
        {
            OffsetsContent = await DownloadFile(SecondaryOffsetsUrl);
            ClientDllContent = await DownloadFile(SecondaryClientDllUrl);
            ButtonsContent = await DownloadFile(SecondaryButtonsUrl);
            Engine2Content = await DownloadFile(SecondaryEngine2Url);
            AnimationSystemContent = await DownloadFile(SecondaryAnimationSystemUrl);
        }

        private static async Task<string> DownloadFile(string url)
        {
            try
            {
                Console.WriteLine($"[偏移查找] 正在下载 {url}");
                string content = await httpClient.GetStringAsync(url);

                Console.WriteLine($"[偏移查找] 已下载 {url}，长度={content.Length}");
                return content;
            }
            catch (Exception ex)
            {
                Console.WriteLine($"[偏移查找] 下载 {url} 出错: {ex.Message}");
                return string.Empty;
            }
        }


        private static void ParseOffsetsFile(string content)
        {
            // regex to match the offsets (global constants)
            var matches = Regex.Matches(content, _offsetRegex);
            Console.WriteLine($"[偏移查找] 在 offsets.cs 中找到 {matches.Count} 个偏移");

            foreach (Match match in matches)
            {
                string name = match.Groups[1].Value;
                int value = Convert.ToInt32(match.Groups[2].Value, 16);
                offsets[name] = value;
            }
        }

        private static void ParseClientDllFile(string content)
        {
            ParseClassOffsets(content, "C_BaseEntity");

            // regex fallback for any extra global consts
            var matches = Regex.Matches(content, _offsetRegex);
            Console.WriteLine($"[偏移查找] 在 client_dll.cs 中额外找到 {matches.Count} 个偏移");

            foreach (Match match in matches)
            {
                string name = match.Groups[1].Value;
                int value = Convert.ToInt32(match.Groups[2].Value, 16);
                if (!offsets.ContainsKey(name))
                {
                    offsets[name] = value;
                }
            }
        }

        private static void ParseAnimationSystemFile(string animationSystemContent)
        {
            // regex to match the offsets (global constants)
            var matches = Regex.Matches(animationSystemContent, _offsetRegex);
            Console.WriteLine($"[偏移查找] 在 offsets.cs 中找到 {matches.Count} 个偏移");

            foreach (Match match in matches)
            {
                string name = match.Groups[1].Value;
                int value = Convert.ToInt32(match.Groups[2].Value, 16);
                offsets[name] = value;
            }
        }

        private static void ParseClassOffsets(string content, string className) // explicitly parse a given class
        {
            string classPattern = $@"public\s+static\s+class\s+{className}\s*\{{([\s\S]*?)\}}";
            var classMatch = Regex.Match(content, classPattern, RegexOptions.Multiline);

            if (!classMatch.Success)
            {
                Console.WriteLine($"[偏移查找] 找不到类 {className}");
                return;
            }

            var matches = Regex.Matches(classMatch.Groups[1].Value, _offsetRegex);

            Console.WriteLine($"[偏移查找] 在类 {className} 中找到 {matches.Count} 个偏移");

            foreach (Match match in matches)
            {
                string name = match.Groups[1].Value;
                int value = Convert.ToInt32(match.Groups[2].Value, 16);
                offsets[name] = value;
            }
        }

        private static void ParseButtonsFile(string content)
        {
            // regex to match the offsets
            var matches = Regex.Matches(content, _offsetRegex);
            Console.WriteLine($"[偏移查找] 在 buttons.cs 中找到 {matches.Count} 个偏移");

            foreach (Match match in matches)
            {
                string name = match.Groups[1].Value;
                int value = Convert.ToInt32(match.Groups[2].Value, 16);
                offsets[name] = value;
            }
        }

        private static void ParseEngine2File(string content)
        {
            // regex to match the offsets
            var matches = Regex.Matches(content, _offsetRegex);
            Console.WriteLine($"[偏移查找] 在 engine2.cs 中找到 {matches.Count} 个偏移");

            foreach (Match match in matches)
            {
                string name = match.Groups[1].Value;
                int value = Convert.ToInt32(match.Groups[2].Value, 16);
                offsets[name] = value;
            }
        }

        private static void UpdateOffsetsClass()
        {
            // grab the static Offsets class
            Type offsetsType = typeof(Titled_Gui.Data.Game.Offsets);
            FieldInfo[] fields = offsetsType.GetFields(BindingFlags.Public | BindingFlags.Static);

            int updatedCount = 0;
            foreach (FieldInfo field in fields)
            {
                string fieldName = field.Name;

                if (FieldNameMappings.TryGetValue(fieldName.Trim(), out List<Offset>? sources))
                {
                    bool found = false;
                    foreach (var source in sources)
                    {
                        if (source.ClassName != null)
                        {
                            ParseClassOffsets(ClientDllContent, source.ClassName);
                        }

                        if (!offsets.TryGetValue(source.Name, out int value))
                            continue;

                        int? currentValue = (int?)field?.GetValue(null);
                        field?.SetValue(null, value);

                        Console.WriteLine(
                            $"[偏移查找] 已更新 {fieldName} 从 0x{currentValue:X} 到 0x{value:X}（来源: {source.Name}，类: {source.ClassName ?? "全局"}）");
                        updatedCount++;
                        found = true;
                        break;
                    }

                    if (!found)
                    {
                        Console.WriteLine($"[偏移查找] 错误: 未找到偏移 {fieldName}（已尝试: {string.Join(", ", sources.Select(s => s.Name))}）");
                    }
                }
                else
                {
                    Console.WriteLine($"[偏移查找] 错误: {fieldName} 未映射");
                }
            }

            Console.WriteLine($"[偏移查找] 已更新: {updatedCount}/{fields.Length} 个偏移");
        }
    }
}
