using System;
using System.IO;
using System.Linq;
using System.Reflection;
using UnityEditor;
using UnityEngine;

namespace Davanci.Nexus.Editor
{
    // AppLovin MAX ships as a .unitypackage (not UPM). We bundle it in InstallerPackages/ like the
    // other SDKs and import it in-place from Nexus Setup — no AppLovin editor window needed. We
    // detect the SDK by its MaxSdk type, set the DAVANCI_ADS define on import, and push the SDK key
    // straight into AppLovinSettings by reflection so the whole setup stays inside Nexus.
    public static class NexusAdsInstaller
    {
        public const string Define = "DAVANCI_ADS";

        // MaxSdk is AppLovin's global entry-point class. TypeExists scans every loaded assembly by
        // short name, so it's found whether MAX compiles into Assembly-CSharp or its own assembly.
        const string DetectType = "MaxSdk";

        public const string DocsUrl =
            "https://developers.applovin.com/en/max/unity/overview/integration";

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

        // The bundled AppLovin .unitypackage, found by prefix so a version bump doesn't break us.
        public static string PackagePath
        {
            get
            {
                if (!Directory.Exists(NexusInstaller.PackagesFolder)) return null;
                return Directory.GetFiles(NexusInstaller.PackagesFolder, "AppLovin*.unitypackage")
                    .OrderByDescending(f => f).FirstOrDefault();
            }
        }

        public static bool PackageBundled => !string.IsNullOrEmpty(PackagePath) && File.Exists(PackagePath);

        // Import the bundled package and set the define, same one-click flow as the other SDKs.
        public static void Import()
        {
            string path = PackagePath;
            if (string.IsNullOrEmpty(path) || !File.Exists(path))
            {
                EditorUtility.DisplayDialog("DavanciNexus",
                    "AppLovin MAX package not found in " + NexusInstaller.PackagesFolder +
                    ".\nDrop the AppLovin-MAX-Unity-Plugin .unitypackage there.", "OK");
                return;
            }

            SetDefine(true);
            NexusPackageUpdater.ImportTracked("applovin_max", path, NexusPackageCatalog.Get("applovin_max")?.version);
        }

        public static void OpenDocs() => Application.OpenURL(DocsUrl);

        public static void SetDefine(bool enabled) => NexusInstaller.SetDefine(Define, enabled);

        // Write the SDK key into AppLovinSettings without opening AppLovin's Integration Manager.
        // Reflection so this editor script compiles even before the MAX SDK is imported.
        public static bool ApplySdkKey(string sdkKey, out string message)
        {
            message = "";
            if (string.IsNullOrEmpty(sdkKey)) { message = "Enter your AppLovin SDK key first."; return false; }

            Type settingsType = AppDomain.CurrentDomain.GetAssemblies()
                .Select(a => a.GetType("AppLovinSettings"))
                .FirstOrDefault(t => t != null);
            if (settingsType == null) { message = "AppLovin MAX isn't installed yet. Import it first."; return false; }

            try
            {
                object instance = settingsType.GetProperty("Instance",
                    BindingFlags.Public | BindingFlags.Static)?.GetValue(null);
                if (instance == null) { message = "Couldn't access AppLovinSettings.Instance."; return false; }

                settingsType.GetProperty("SdkKey", BindingFlags.Public | BindingFlags.Instance)
                    ?.SetValue(instance, sdkKey);

                // Persist: prefer the SDK's own SaveAsync(), fall back to marking the asset dirty.
                var save = settingsType.GetMethod("SaveAsync", BindingFlags.Public | BindingFlags.Instance);
                if (save != null) save.Invoke(instance, null);
                if (instance is UnityEngine.Object obj)
                {
                    EditorUtility.SetDirty(obj);
                    AssetDatabase.SaveAssets();
                }

                message = "SDK key written to AppLovinSettings.";
                return true;
            }
            catch (Exception e)
            {
                message = "Failed to write SDK key: " + e.Message;
                return false;
            }
        }
    }
}
