#if UNITY_ANDROID
using System;
using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Text.RegularExpressions;
using UnityEditor.Android;
using UnityEngine;

namespace Topon_Adapter.Editor
{
    public sealed class ToponAndroidDebuggerDependencyPostProcessor : IPostGenerateGradleAndroidProject
    {
        private const string Tag = "[TopOn Build]";
        private const string DebuggerDependency = "com.anythink.sdk:debugger-ui:+";
        private const string DebuggerDependencyMarker = "com.anythink.sdk:debugger-ui";
        private const string VerbtoDependencyMarker = "com.verbto.tools:util";
        private const string DebuggerRepositoryUrl = "https://jfrog.anythinktech.com/artifactory/debugger";
        private const string DepsStart = "// TopOn Debugger UI Dependencies Start";
        private const string DepsEnd = "// TopOn Debugger UI Dependencies End";
        private const string VerbtoDepsStart = "// TopOn Verbto Util Dependency Start";
        private const string VerbtoDepsEnd = "// TopOn Verbto Util Dependency End";
        private const string ReposStart = "// TopOn Debugger UI Repository Start";
        private const string ReposEnd = "// TopOn Debugger UI Repository End";

        public int callbackOrder => int.MaxValue;

        public void OnPostGenerateGradleAndroidProject(string path)
        {
            var settings = ToponBuildSettingsStore.GetActiveForCurrentBuild();
            try
            {
                ProcessGeneratedProject(path, settings);
            }
            finally
            {
                ToponBuildSettingsStore.ClearActiveBuildSettings();
            }
        }

        public static void ProcessGeneratedProject(string path, ToponBuildSettings settings)
        {
            if (settings == null)
            {
                settings = ToponBuildSettingsStore.CreateDefault();
            }

            var gradleRoot = GetGradleRoot(path);
            var gradleFiles = new[]
            {
                Path.Combine(path, "build.gradle"),
                Path.Combine(gradleRoot, "launcher", "build.gradle"),
                Path.Combine(gradleRoot, "build.gradle")
            };
            var forceVerbtoUtilVersion = settings.forceVerbtoUtilVersion;
            var verbtoDependency = ToponBuildSettingsStore.GetVerbtoUtilDependency(settings);

            foreach (var gradleFile in gradleFiles)
            {
                StripManagedDependenciesFromGradleFile(gradleFile, forceVerbtoUtilVersion);
            }

            StripManagedDependenciesFromGradleFile(Path.Combine(gradleRoot, "settings.gradle"), forceVerbtoUtilVersion);

            if (settings.enableDebuggerUI || forceVerbtoUtilVersion)
            {
                InjectRepository(Path.Combine(gradleRoot, "settings.gradle"));
                InjectRepository(Path.Combine(gradleRoot, "build.gradle"));
            }

            if (settings.enableDebuggerUI)
            {
                InjectDebuggerDependency(Path.Combine(path, "build.gradle"));
                Debug.Log($"{Tag} DebugUI dependency enabled for this build.");
            }
            else
            {
                if (settings.stripResolvedDebuggerArtifacts)
                {
                    RemoveGeneratedDebuggerArtifacts(gradleRoot);
                }

                Debug.Log($"{Tag} DebugUI dependency disabled for this build.");
            }

            if (forceVerbtoUtilVersion)
            {
                InjectVerbtoUtilDependency(Path.Combine(path, "build.gradle"), verbtoDependency);
                RemoveGeneratedStaleVerbtoUtilArtifacts(gradleRoot, verbtoDependency);
                Debug.Log($"{Tag} Verbto util dependency forced to {verbtoDependency}.");
            }
            else
            {
                Debug.Log($"{Tag} Verbto util dependency is not modified by TopOn build settings.");
            }
        }

        private static string GetGradleRoot(string unityLibraryPath)
        {
#if UNITY_2019_3_OR_NEWER
            return Path.GetFullPath(Path.Combine(unityLibraryPath, ".."));
#else
            return Path.GetFullPath(unityLibraryPath);
#endif
        }

        private static void StripManagedDependenciesFromGradleFile(string filePath, bool forceVerbtoUtilVersion)
        {
            if (string.IsNullOrEmpty(filePath) || !File.Exists(filePath))
            {
                return;
            }

            var content = File.ReadAllText(filePath);
            var original = content;
            content = RemoveMarkedBlock(content, DepsStart, DepsEnd);
            content = RemoveMarkedBlock(content, VerbtoDepsStart, VerbtoDepsEnd);
            content = RemoveMarkedBlock(content, ReposStart, ReposEnd);
            content = RemoveLinesContaining(content, DebuggerDependencyMarker);
            if (forceVerbtoUtilVersion)
            {
                content = RemoveLinesContaining(content, VerbtoDependencyMarker);
            }

            if (!string.Equals(original, content, StringComparison.Ordinal))
            {
                File.WriteAllText(filePath, content);
            }
        }

        private static void InjectDebuggerDependency(string buildGradlePath)
        {
            InjectDependencyBlock(buildGradlePath, DepsStart, DepsEnd, DebuggerDependency);
        }

        private static void InjectVerbtoUtilDependency(string buildGradlePath, string dependency)
        {
            InjectDependencyBlock(buildGradlePath, VerbtoDepsStart, VerbtoDepsEnd, dependency);
        }

        private static void InjectDependencyBlock(string buildGradlePath, string startMarker, string endMarker, string dependency)
        {
            if (!File.Exists(buildGradlePath))
            {
                Debug.LogWarning($"{Tag} build.gradle not found: {buildGradlePath}");
                return;
            }

            if (string.IsNullOrWhiteSpace(dependency))
            {
                Debug.LogWarning($"{Tag} dependency is empty, skip injecting {startMarker}.");
                return;
            }

            var content = File.ReadAllText(buildGradlePath);
            var block = new StringBuilder();
            block.AppendLine(startMarker);
            block.AppendLine($"    implementation '{dependency.Trim()}'");
            block.AppendLine($"    {endMarker}");

            var pattern = new Regex(@"(dependencies\s*\{)");
            if (!pattern.IsMatch(content))
            {
                Debug.LogWarning($"{Tag} dependencies block not found: {buildGradlePath}");
                return;
            }

            content = pattern.Replace(content, match => match.Groups[1].Value + "\n    " + block, 1);
            File.WriteAllText(buildGradlePath, content);
        }

        private static void InjectRepository(string gradlePath)
        {
            if (!File.Exists(gradlePath))
            {
                return;
            }

            var content = File.ReadAllText(gradlePath);
            if (content.Contains(DebuggerRepositoryUrl))
            {
                return;
            }

            var block = $"{ReposStart}\n        maven {{ url '{DebuggerRepositoryUrl}' }}\n        {ReposEnd}";
            Regex pattern;
            if (Path.GetFileName(gradlePath).Equals("settings.gradle", StringComparison.OrdinalIgnoreCase))
            {
                pattern = new Regex(@"(dependencyResolutionManagement\s*\{[\s\S]*?repositories\s*\{)");
            }
            else
            {
                block = $"{ReposStart}\n    maven {{ url '{DebuggerRepositoryUrl}' }}\n    {ReposEnd}";
                pattern = new Regex(@"(repositories\s*\{)");
            }

            if (!pattern.IsMatch(content))
            {
                return;
            }

            content = pattern.Replace(content, match => match.Groups[1].Value + "\n        " + block, 1);
            File.WriteAllText(gradlePath, content);
        }

        private static void RemoveGeneratedDebuggerArtifacts(string gradleRoot)
        {
            if (string.IsNullOrWhiteSpace(gradleRoot) || !Directory.Exists(gradleRoot))
            {
                return;
            }

            var root = Path.GetFullPath(gradleRoot).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
            foreach (var path in Directory.GetFiles(root, "*", SearchOption.AllDirectories))
            {
                if (!ToponBuildSettingsStore.IsDebuggerArtifactFileName(Path.GetFileName(path)))
                {
                    continue;
                }

                var fullPath = Path.GetFullPath(path);
                if (!fullPath.StartsWith(root, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                try
                {
                    File.Delete(fullPath);
                    Debug.Log($"{Tag} Removed generated debugger artifact: {fullPath}");
                }
                catch (Exception exception)
                {
                    Debug.LogWarning($"{Tag} Failed to remove generated debugger artifact: {exception.Message}");
                }
            }
        }

        private static void RemoveGeneratedStaleVerbtoUtilArtifacts(string gradleRoot, string expectedDependency)
        {
            if (string.IsNullOrWhiteSpace(gradleRoot) || !Directory.Exists(gradleRoot))
            {
                return;
            }

            var root = Path.GetFullPath(gradleRoot).TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar);
            foreach (var path in Directory.GetFiles(root, "*", SearchOption.AllDirectories))
            {
                var fileName = Path.GetFileName(path);
                if (!ToponBuildSettingsStore.IsVerbtoUtilArtifactFileName(fileName) ||
                    ToponBuildSettingsStore.IsExpectedVerbtoUtilArtifactFileName(fileName, expectedDependency))
                {
                    continue;
                }

                var fullPath = Path.GetFullPath(path);
                if (!fullPath.StartsWith(root, StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                try
                {
                    File.Delete(fullPath);
                    Debug.Log($"{Tag} Removed stale verbto util artifact: {fullPath}");
                }
                catch (Exception exception)
                {
                    Debug.LogWarning($"{Tag} Failed to remove stale verbto util artifact: {exception.Message}");
                }
            }
        }

        private static string RemoveMarkedBlock(string content, string startMarker, string endMarker)
        {
            var pattern = new Regex($@"\s*{Regex.Escape(startMarker)}[\s\S]*?{Regex.Escape(endMarker)}\s*");
            return pattern.Replace(content, "\n");
        }

        private static string RemoveLinesContaining(string content, params string[] markers)
        {
            var lines = content.Replace("\r\n", "\n").Replace('\r', '\n').Split('\n');
            var kept = new List<string>();
            foreach (var line in lines)
            {
                var remove = false;
                foreach (var marker in markers)
                {
                    if (line.Contains(marker))
                    {
                        remove = true;
                        break;
                    }
                }

                if (!remove)
                {
                    kept.Add(line);
                }
            }

            return string.Join("\n", kept);
        }
    }
}
#endif
