using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEditor.Build;
using UnityEditor.Build.Reporting;
using UnityEngine;

namespace Alibabacloud.Rum.Unity.Windows.Editor
{
    /// <summary>
    /// Build post processor for Windows platform
    /// Handles DLL deployment after build
    /// </summary>
    public class WindowsBuildPostProcessor : IPostprocessBuildWithReport
    {
        private const string PackageName = "com.alibabacloud.rum.unity";
        private const string DllFileName = "alibabacloud_rum.dll";

        public int callbackOrder => 1;

        public void OnPostprocessBuild(BuildReport report)
        {
            if (report.summary.platform == BuildTarget.StandaloneWindows ||
                report.summary.platform == BuildTarget.StandaloneWindows64)
            {
                CopyNativeDlls(report);
            }
        }

        private void CopyNativeDlls(BuildReport report)
        {
            string buildOutputDir = Path.GetDirectoryName(report.summary.outputPath);
            if (string.IsNullOrEmpty(buildOutputDir))
            {
                Debug.LogWarning("[AlibabacloudRUM] Could not determine build output directory");
                return;
            }

            // Determine architecture based on build target
            bool is64Bit = report.summary.platform == BuildTarget.StandaloneWindows64;
            string archSubdir = is64Bit ? "x86_64" : "x86";

            // Collect candidate source directories. Order matters: try host project
            // layout first, then UPM package layout, then fall back to resolved
            // package path via PackageInfo.
            var possibleSourceDirs = new List<string>
            {
                // Host project (when SDK source is dropped into Assets/)
                Path.Combine(Application.dataPath, "Plugins", archSubdir),
                Path.Combine(Application.dataPath, "AlibabacloudRUM", "Plugins", archSubdir),
                // UPM package layout (relative path from project root)
                Path.GetFullPath(Path.Combine("Packages", PackageName, "Runtime", "Plugins", archSubdir)),
            };

            // Resolve package physical path via PackageManager (handles tarball/git/local UPM installs)
            try
            {
                var packageInfo = UnityEditor.PackageManager.PackageInfo.FindForAssembly(typeof(WindowsBuildPostProcessor).Assembly);
                if (packageInfo != null && !string.IsNullOrEmpty(packageInfo.resolvedPath))
                {
                    possibleSourceDirs.Add(
                        Path.Combine(packageInfo.resolvedPath, "Runtime", "Plugins", archSubdir));
                }
            }
            catch (System.Exception e)
            {
                Debug.LogWarning($"[AlibabacloudRUM] PackageInfo.FindForAssembly failed: {e.Message}");
            }

            // Find the directory that contains alibabacloud_rum.dll
            string foundSourceDir = null;
            foreach (var dir in possibleSourceDirs)
            {
                if (!string.IsNullOrEmpty(dir) && File.Exists(Path.Combine(dir, DllFileName)))
                {
                    foundSourceDir = dir;
                    break;
                }
            }

            if (string.IsNullOrEmpty(foundSourceDir))
            {
                Debug.LogWarning("[AlibabacloudRUM] Native DLL not found. Searched paths:\n" +
                    string.Join("\n", possibleSourceDirs.Select(d => $"  - {d}")));
                return;
            }

            // Target directory: GameName_Data/Plugins/<arch>/
            // This is the SINGLE source of truth for the DLL. Do NOT also copy
            // to the build root, otherwise Windows loads two separate instances
            // of the same DLL (different base addresses, independent globals/heap)
            // and pointers crossing between them cause hard crashes.
            string buildName = Path.GetFileNameWithoutExtension(report.summary.outputPath);
            string dataDir = Path.Combine(buildOutputDir, $"{buildName}_Data");
            string pluginsArchDir = Path.Combine(dataDir, "Plugins", archSubdir);

            // Remove any stray copy at the build root from previous builds to
            // prevent the double-load problem.
            string strayRootDll = Path.Combine(buildOutputDir, DllFileName);
            if (File.Exists(strayRootDll))
            {
                try
                {
                    File.Delete(strayRootDll);
                    Debug.Log($"[AlibabacloudRUM] Removed stray root DLL: {strayRootDll}");
                }
                catch (System.Exception e)
                {
                    Debug.LogWarning($"[AlibabacloudRUM] Failed to remove stray root DLL: {e.Message}");
                }
            }

            try
            {
                Directory.CreateDirectory(pluginsArchDir);
            }
            catch (System.Exception e)
            {
                Debug.LogWarning($"[AlibabacloudRUM] Failed to create {pluginsArchDir}: {e.Message}");
                return;
            }

            // Copy ALL non-meta files (DLL + any dependency DLLs/PDBs) into
            // the canonical Plugins/<arch>/ directory. Unity may have already
            // placed the main DLL there via PluginImporter; we overwrite to
            // ensure the latest version and to ship dependency DLLs alongside.
            int copiedCount = 0;
            foreach (var filePath in Directory.GetFiles(foundSourceDir))
            {
                if (filePath.EndsWith(".meta", System.StringComparison.OrdinalIgnoreCase))
                {
                    continue;
                }

                string fileName = Path.GetFileName(filePath);
                string destPath = Path.Combine(pluginsArchDir, fileName);
                try
                {
                    File.Copy(filePath, destPath, true);
                    copiedCount++;
                }
                catch (System.Exception e)
                {
                    Debug.LogWarning($"[AlibabacloudRUM] Failed to copy {fileName}: {e.Message}");
                }
            }

            Debug.Log($"[AlibabacloudRUM] Deployed {copiedCount} file(s) from {foundSourceDir} to {pluginsArchDir}");
        }
    }
}
