using System.IO;
using System.IO.Compression;
using UnityEditor;
using UnityEditor.Build;
using UnityEngine;

namespace Davanci.Nexus.Editor
{
    // Install / remove the InMobi Choice CMP native SDK (GDPR / US-privacy consent).
    //
    // Unlike the other bundled SDKs (which ship as .unitypackage), InMobi Choice is a set of native
    // plugins — an iOS .xcframework, an ObjC++ bridge, and an Android .aar. To keep them OUT of the
    // project until the user explicitly installs from Nexus Setup → Privacy (GDPR), the payload is
    // staged under InstallerPackages/InMobiCMP with neutral extensions (.zip/.txt/.bytes) so Unity
    // never compiles or links them while staged. Install copies them into Assets/Plugins and sets
    // DAVANCI_INMOBI_CMP; Remove deletes them and clears the define so runtime code compiles out.
    [InitializeOnLoad]
    public static class NexusInMobiCmpInstaller
    {
        public const string Define = "DAVANCI_INMOBI_CMP";

        const string StageDir = "Assets/DavanciNexus/InstallerPackages/InMobiCMP";
        const string StageXcframeworkZip = StageDir + "/InMobiCMP.xcframework.zip";
        const string StageAar = StageDir + "/inmobicmp-2.4.3.aar.bytes";
        const string StageBridge = StageDir + "/NexusInMobiCmpBridge.mm.txt";

        const string IosDir = "Assets/Plugins/iOS";
        const string AndroidDir = "Assets/Plugins/Android";
        const string DestXcframework = IosDir + "/InMobiCMP.xcframework";
        const string DestBridge = IosDir + "/NexusInMobiCmpBridge.mm";
        const string DestAar = AndroidDir + "/inmobicmp-2.4.3.aar";

        static readonly NamedBuildTarget[] Targets =
        {
            NamedBuildTarget.Standalone,
            NamedBuildTarget.iOS,
            NamedBuildTarget.Android,
            NamedBuildTarget.tvOS,
        };

        // The plugin files exist in the project → the SDK is integrated.
        public static bool Installed => Directory.Exists(DestXcframework) || File.Exists(DestAar);

        // The staged payload is available to install from.
        public static bool PayloadAvailable =>
            File.Exists(StageXcframeworkZip) && File.Exists(StageAar) && File.Exists(StageBridge);

        public static bool DefineSet => NexusInstaller.HasDefine(Define);

        static NexusInMobiCmpInstaller()
        {
            // Keep the define in lock-step with the plugin files: if they were removed outside Nexus
            // (or the project was cloned without them), the define is cleared so runtime code compiles.
            EditorApplication.delayCall += Sync;
        }

        static void Sync()
        {
            bool present = Installed;
            foreach (var t in Targets)
                SetDefine(t, present);

            // Overwrite the live iOS bridge when the staged copy is newer/different — users who
            // installed before a bridge fix don't need Remove+Install to pick up callback changes.
            if (present && File.Exists(StageBridge))
                SyncBridgeFromStage();
        }

        static void SyncBridgeFromStage()
        {
            try
            {
                if (File.Exists(DestBridge))
                {
                    var stage = File.ReadAllText(StageBridge);
                    if (stage == File.ReadAllText(DestBridge)) return;
                }
                Directory.CreateDirectory(IosDir);
                File.Copy(StageBridge, DestBridge, true);
                AssetDatabase.Refresh();
                Debug.Log("[Nexus] InMobi CMP iOS bridge updated from installer payload.");
            }
            catch (System.Exception e)
            {
                Debug.LogWarning("[Nexus] InMobi CMP bridge sync failed: " + e.Message);
            }
        }

        public static void Install()
        {
            if (Installed) return;
            if (!PayloadAvailable)
            {
                EditorUtility.DisplayDialog("DavanciNexus",
                    "InMobi Choice CMP payload not found under\n" + StageDir + ".\n\n" +
                    "Re-import DavanciNexus so the installer files are present.", "OK");
                return;
            }

            try
            {
                Directory.CreateDirectory(IosDir);
                Directory.CreateDirectory(AndroidDir);

                if (Directory.Exists(DestXcframework))
                    Directory.Delete(DestXcframework, true);
                ZipFile.ExtractToDirectory(StageXcframeworkZip, IosDir);

                File.Copy(StageBridge, DestBridge, true);
                File.Copy(StageAar, DestAar, true);
            }
            catch (System.Exception e)
            {
                EditorUtility.DisplayDialog("DavanciNexus",
                    "Failed to install InMobi Choice CMP:\n" + e.Message, "OK");
                Debug.LogError("[Nexus] InMobi CMP install failed: " + e);
                return;
            }

            AssetDatabase.Refresh();
            foreach (var t in Targets)
                SetDefine(t, true);

            Debug.Log("[Nexus] InMobi Choice CMP installed. DAVANCI_INMOBI_CMP set.");
            NotifyUiRefresh();
        }

        public static void Remove()
        {
            AssetDatabase.DeleteAsset(DestXcframework);
            AssetDatabase.DeleteAsset(DestBridge);
            AssetDatabase.DeleteAsset(DestAar);

            // Belt-and-braces for anything AssetDatabase missed (stray files/metas).
            SafeDeleteDir(DestXcframework);
            SafeDeleteFile(DestBridge);
            SafeDeleteFile(DestAar);

            foreach (var t in Targets)
                SetDefine(t, false);

            AssetDatabase.Refresh();
            Debug.Log("[Nexus] InMobi Choice CMP removed. DAVANCI_INMOBI_CMP cleared.");
            NotifyUiRefresh();
        }

        static void SafeDeleteDir(string path)
        {
            try
            {
                if (Directory.Exists(path)) Directory.Delete(path, true);
                if (File.Exists(path + ".meta")) File.Delete(path + ".meta");
            }
            catch { /* ignore */ }
        }

        static void SafeDeleteFile(string path)
        {
            try
            {
                if (File.Exists(path)) File.Delete(path);
                if (File.Exists(path + ".meta")) File.Delete(path + ".meta");
            }
            catch { /* ignore */ }
        }

        static void NotifyUiRefresh()
        {
            EditorApplication.delayCall += () =>
            {
                NexusSetupWindow.RefreshIfOpen();
                NexusDoctorWindow.RefreshIfOpen();
            };
        }

        public static void SetDefine(bool enabled)
        {
            foreach (var t in Targets)
                SetDefine(t, enabled);
        }

        static void SetDefine(NamedBuildTarget target, bool enabled)
        {
            var symbols = PlayerSettings.GetScriptingDefineSymbols(target);
            var list = symbols.Split(';');
            bool has = false;
            for (int i = 0; i < list.Length; i++)
                if (list[i].Trim() == Define) { has = true; break; }

            if (enabled == has) return;

            if (enabled)
                PlayerSettings.SetScriptingDefineSymbols(target,
                    string.IsNullOrEmpty(symbols) ? Define : symbols + ";" + Define);
            else
            {
                var rebuilt = new System.Collections.Generic.List<string>();
                foreach (var s in list)
                {
                    var d = s.Trim();
                    if (d.Length == 0 || d == Define) continue;
                    rebuilt.Add(d);
                }
                PlayerSettings.SetScriptingDefineSymbols(target, string.Join(";", rebuilt));
            }
        }
    }
}
