using System;
using System.Collections;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using UnityEditor;
using UnityEngine;
using UnityEngine.Networking;
using Yodo1.MAS;

[InitializeOnLoad]
public class IntegrationManager : EditorWindow
{
    private const float editorWindowMinWidth = 600f;
    private const float editorWindowMinLength = 950f;
    private const float networkFieldMinWidth = 100f;
    private const float versionFieldMinWidth = 190f;
    private const float actionFieldWidth = 60f;

    private static readonly GUILayoutOption networkWidthOption = GUILayout.Width(networkFieldMinWidth);
    private static readonly GUILayoutOption versionWidthOption = GUILayout.Width(versionFieldMinWidth);
    private static readonly GUILayoutOption fieldWidth = GUILayout.Width(actionFieldWidth);

    private GUIStyle headerLabelStyle;
    private GUIStyle contentLabelStyle;

    private int platformTabSelected;
    private int prevPlatformTabSelected;

    private Yodo1AdNetworkConfig adNetworkConfig;
    private Yodo1AdNetwork[] android;
    private Yodo1AdNetwork[] ios;
    private Yodo1AdNetworkConfigCacheData androidCachedData;
    private Yodo1AdNetworkConfigCacheData iosCachedData;
    private float sdkSize;

    private static string packageName = string.Empty;
    private static bool importPackageCompleted;

    private UnityWebRequest webRequest;
    private Texture installIcon;

    #region Platform Helper

    private Yodo1AdNetwork[] CurrentNetworks => platformTabSelected == 0 ? android : ios;

    private Yodo1AdNetworkConfigCacheData CurrentCachedData
    {
        get => platformTabSelected == 0 ? androidCachedData : iosCachedData;
        set
        {
            if (platformTabSelected == 0)
                androidCachedData = value;
            else
                iosCachedData = value;
        }
    }

    private SdkGroupType CurrentSdkGroupType =>
        platformTabSelected == 0 ? SdkGroupType.AndroidStandard : SdkGroupType.IosStandard;

    private void RefreshCurrentCachedData()
    {
        CurrentCachedData = platformTabSelected == 0
            ? Yodo1AdNetworkManager.GetInstance().GetCachedAndroidAdNetworksInfo()
            : Yodo1AdNetworkManager.GetInstance().GetCachedIosAdNetworksInfo();
    }

    #endregion

    #region Lifecycle

    static IntegrationManager()
    {
        AssetDatabase.importPackageCompleted += OnImportPackageCompleted;
    }

    /// <summary>
    /// Handles post-import work when the MAS (Rivendell) package is installed.
    /// Ensures the Android plugins folder exists before dependency updates so EDM can copy Gradle templates.
    /// </summary>
    private static void OnImportPackageCompleted(string importedPackageName)
    {
        if (importedPackageName.Contains("Rivendell"))
        {
#if UNITY_ANDROID
            if (!Yodo1AdUtils.IsGooglePlayVersion()) return;
#endif
            EnsureAndroidPluginsFolderForEdm();
            UpdateAdNetworkAndDependencies();
            importPackageCompleted = true;
        }
    }

    /// <summary>
    /// Initializes ad network config, merges cached selections into dependency files, and refreshes assets.
    /// Callers include the Rivendell import callback and <see cref="Yodo1AdAssetsImporter"/>.
    /// </summary>
    public static void UpdateAdNetworkAndDependencies()
    {
#if UNITY_ANDROID
        if (!Yodo1AdUtils.IsGooglePlayVersion()) return;
#endif
        EnsureAndroidPluginsFolderForEdm();
        Yodo1AdNetworkManager.GetInstance().InitAdNetworkConfig();
        Yodo1AdNetworkManager.GetInstance().CheckDependenciesFileByCachedAdNetworks();
    }

    /// <summary>
    /// Creates <c>Assets/Plugins/Android</c> on disk if missing. Required because EDM copies
    /// <c>mainTemplate.gradle</c> there during Play Services / Android resolution; a missing parent directory causes <see cref="DirectoryNotFoundException"/>.
    /// </summary>
    private static void EnsureAndroidPluginsFolderForEdm()
    {
        Directory.CreateDirectory(Path.Combine(Application.dataPath, "Plugins", "Android"));
    }

    [MenuItem("Yodo1/MAS/Integration Manager", false, 100)]
    static void Init()
    {
        var window = (IntegrationManager)GetWindow(typeof(IntegrationManager), true, "Yodo1 Integration Manager");
        window.minSize = new Vector2(editorWindowMinWidth, editorWindowMinLength);
        window.maxSize = window.minSize;
        window.Show();
    }

    [MenuItem("Yodo1/MAS/Integration Manager", true, 100)]
    static bool ValidateInit()
    {
#if UNITY_ANDROID
        return Yodo1AdUtils.IsGooglePlayVersion();
#else
        return true;
#endif
    }

    private void Awake()
    {
        headerLabelStyle = new GUIStyle(EditorStyles.label)
        {
            fontSize = 12,
            fontStyle = FontStyle.Bold,
            fixedHeight = 18
        };
        contentLabelStyle = new GUIStyle(EditorStyles.label)
        {
            fontSize = 12,
            fontStyle = FontStyle.Bold,
            fixedHeight = 18,
            alignment = TextAnchor.MiddleCenter
        };
        installIcon = AssetDatabase.LoadAssetAtPath<Texture>("Assets/Yodo1/MAS/Editor/Resources/asset1.png");
        EditorApplication.delayCall += LoadAndRepaint;
    }

    private void OnInspectorUpdate()
    {
        if (importPackageCompleted)
        {
            importPackageCompleted = false;
            LoadAndRepaint();
        }
    }

    private void LoadAndRepaint()
    {
        LoadPluginData();
        Repaint();
    }

    #endregion

    #region Data Loading

    private void LoadPluginData()
    {
        Yodo1AdNetworkManager.GetInstance().InitAdNetworkConfig();
        adNetworkConfig = Yodo1AdNetworkManager.GetInstance().GetAdNetworkConfig();
        if (adNetworkConfig == null) return;

        if (adNetworkConfig.ios != null && adNetworkConfig.ios.Length > 0)
        {
            adNetworkConfig.ios = adNetworkConfig.ios
                .OrderBy(n => n.displayName.FirstOrDefault())
                .ToArray();
        }

        if (adNetworkConfig.android != null && adNetworkConfig.android.Length > 0)
        {
            adNetworkConfig.android = adNetworkConfig.android
                .OrderBy(n => n.displayName.FirstOrDefault())
                .ToArray();
        }

        android = adNetworkConfig.android;
        ios = adNetworkConfig.ios;

        androidCachedData = Yodo1AdNetworkManager.GetInstance().GetCachedAndroidAdNetworksInfo();
        iosCachedData = Yodo1AdNetworkManager.GetInstance().GetCachedIosAdNetworksInfo();
        CalculateSDKSize();
    }

    private string CurrentAdNetworkVersion()
    {
        return Yodo1AdNetworkManager.GetInstance().GetCurMakSdkVersion();
    }

    private string LatestAdNetworkVersion()
    {
        return adNetworkConfig != null ? adNetworkConfig.latestSdkversion : string.Empty;
    }

    private string GetUpgradeDownloadUrl()
    {
        return adNetworkConfig != null ? adNetworkConfig.sdkDownloadUrl : string.Empty;
    }

    #endregion

    #region Network Operations

    /// <summary>
    /// True when a non-empty list is stored in settings. When false, the UI uses implicit behaviour:
    /// every non-hidden network (<see cref="Yodo1AdNetwork.status"/> != 1) is treated as installed.
    /// </summary>
    private static bool HasExplicitSavedNetworkList(Yodo1AdNetworkConfigCacheData cachedData)
    {
        return cachedData?.networks != null && cachedData.networks.Count > 0;
    }

    /// <summary>
    /// Writes platform group and MAS SDK version fields required when persisting an explicit selection for the first time.
    /// </summary>
    private void StampExplicitSelectionMetadata(Yodo1AdNetworkConfigCacheData cachedData)
    {
        cachedData.sdkGroupType = CurrentSdkGroupType;
        cachedData.sdkVersion = adNetworkConfig.sdkVersion;
        cachedData.latestSdkVersion = adNetworkConfig.latestSdkversion;
    }

    /// <summary>
    /// Builds the list of network names that are "on" under the implicit default: all visible (non-hidden) networks
    /// on the current tab, optionally omitting <paramref name="excludeName"/>.
    /// </summary>
    private List<string> BuildDefaultInstalledNetworkNames(string excludeName)
    {
        var networks = CurrentNetworks;
        var list = new List<string>();
        if (networks == null) return list;

        foreach (var network in networks)
        {
            if (network.status != 1 && !string.Equals(network.name, excludeName, StringComparison.Ordinal))
            {
                list.Add(network.name);
            }
        }
        return list;
    }

    /// <summary>
    /// First transition from implicit default to a persisted list: default-all visible networks minus <paramref name="removedName"/>.
    /// </summary>
    private void MaterializeExplicitSelectionRemovingNetwork(Yodo1AdNetworkConfigCacheData cachedData, string removedName)
    {
        cachedData.networks = BuildDefaultInstalledNetworkNames(removedName);
        StampExplicitSelectionMetadata(cachedData);
    }

    /// <summary>
    /// First transition from implicit default to a persisted list: default-all visible networks, ensuring <paramref name="addedName"/> is included (e.g. installing a hidden network).
    /// </summary>
    private void MaterializeExplicitSelectionIncludingNetwork(Yodo1AdNetworkConfigCacheData cachedData, string addedName)
    {
        List<string> list = BuildDefaultInstalledNetworkNames(null);
        if (!string.IsNullOrEmpty(addedName) && !list.Contains(addedName))
        {
            list.Add(addedName);
        }
        cachedData.networks = list;
        StampExplicitSelectionMetadata(cachedData);
    }

    private bool IsNetworkInstalled(Yodo1AdNetwork adNetwork)
    {
        var cachedData = CurrentCachedData;
        if (cachedData == null) return false;

        if (HasExplicitSavedNetworkList(cachedData))
        {
            return cachedData.networks.Contains(adNetwork.name);
        }

        return adNetwork.status != 1;
    }

    private void RemoveAdNetwork(Yodo1AdNetwork adNetwork)
    {
        var cachedData = CurrentCachedData;

        if (HasExplicitSavedNetworkList(cachedData))
        {
            cachedData.networks.Remove(adNetwork.name);
        }
        else
        {
            MaterializeExplicitSelectionRemovingNetwork(cachedData, adNetwork.name);
        }

        Yodo1AdNetworkManager.GetInstance().UpdateAdNetworksInfo(cachedData);
        RefreshCurrentCachedData();
        CalculateSDKSize();
        Repaint();
    }

    private void InstallAdNetwork(Yodo1AdNetwork adNetwork)
    {
        var cachedData = CurrentCachedData;

        if (HasExplicitSavedNetworkList(cachedData))
        {
            if (!cachedData.networks.Contains(adNetwork.name))
            {
                cachedData.networks.Add(adNetwork.name);
            }
        }
        else
        {
            MaterializeExplicitSelectionIncludingNetwork(cachedData, adNetwork.name);
        }

        Yodo1AdNetworkManager.GetInstance().UpdateAdNetworksInfo(cachedData);
        RefreshCurrentCachedData();
        CalculateSDKSize();
        Repaint();
    }

    private void CalculateSDKSize()
    {
        sdkSize = 0f;
        var networks = CurrentNetworks;
        if (networks != null)
        {
            foreach (var network in networks)
            {
                if (IsNetworkInstalled(network))
                {
                    sdkSize += network.size;
                }
            }
        }
        sdkSize = Mathf.Round(sdkSize * 100f) / 100f;
    }

    #endregion

    #region Upgrade / Download

    private void UpgradeButtonClicked()
    {
        var url = GetUpgradeDownloadUrl();
        var packageComponents = url.Split(new[] { ".unitypackage" }, StringSplitOptions.None);
        packageName = packageComponents[0].Substring(packageComponents[0].LastIndexOf("/") + 1);
        if (packageName.Contains("-"))
        {
            var components = packageName.Split(new[] { "-beta" }, StringSplitOptions.None);
            packageName = components[0];
        }
        EditorCoroutineRunner.StartEditorCoroutine(DownloadPlugin(url, packageName));
    }

    private IEnumerator DownloadPlugin(string downloadUrl, string version)
    {
        var path = Path.Combine(Application.temporaryCachePath, version + ".unitypackage");
        var downloadHandler = new DownloadHandlerFile(path);
        webRequest = new UnityWebRequest(downloadUrl)
        {
            method = UnityWebRequest.kHttpVerbGET,
            downloadHandler = downloadHandler
        };

        var operation = webRequest.SendWebRequest();
        while (!operation.isDone)
        {
            yield return null;
        }

#if UNITY_2020_1_OR_NEWER
        if (webRequest.result != UnityWebRequest.Result.Success)
#elif UNITY_2017_2_OR_NEWER
        if (webRequest.isNetworkError || webRequest.isHttpError)
#else
        if (webRequest.isError)
#endif
        {
            Debug.LogWarning(Yodo1U3dMas.TAG + "Download failed: " + webRequest.error);
        }
        else
        {
            AssetDatabase.ImportPackage(path, true);
        }

        webRequest.Dispose();
        webRequest = null;
    }

    #endregion

    #region GUI

    void OnGUI()
    {
        GUILayout.Space(10);
        DrawPluginDetails();
        GUIUtility.ExitGUI();
    }

    private void DrawPluginDetails()
    {
        GUILayout.Space(10);
        GUILayout.BeginHorizontal();
        GUILayout.Space(10);
        using (new EditorGUILayout.VerticalScope("box"))
        {
            DrawHeaders();
            DrawPluginDetailRow("Standard", CurrentAdNetworkVersion(), LatestAdNetworkVersion());
        }
        GUILayout.Space(5);
        GUILayout.EndHorizontal();

        platformTabSelected = GUILayout.Toolbar(platformTabSelected, new[] { "Android", "iOS" });
        if (platformTabSelected != prevPlatformTabSelected)
        {
            CalculateSDKSize();
            prevPlatformTabSelected = platformTabSelected;
        }

        GUILayout.Space(10);
        GUILayout.Label("Mediation network details", headerLabelStyle);
        GUILayout.Space(10);
        using (new EditorGUILayout.VerticalScope("box"))
        {
            DrawHeaderNetworks();
            GUILayout.Space(5);
            var networks = CurrentNetworks;
            if (networks != null)
            {
                foreach (var network in networks)
                {
                    DrawNetworkDetailRow(network);
                }
            }
        }

        GUILayout.Space(40);
        using (new EditorGUILayout.HorizontalScope())
        {
            GUILayout.FlexibleSpace();
            if (platformTabSelected == 0)
            {
                EditorGUILayout.LabelField(new GUIContent("Current Size : " + sdkSize + " MB"), contentLabelStyle);
            }
            GUILayout.FlexibleSpace();
        }
        GUILayout.EndHorizontal();
    }

    private void DrawPluginDetailRow(string platform, string currentVersion, string latestVersion)
    {
        using (new EditorGUILayout.HorizontalScope())
        {
            GUILayout.Space(5);
            EditorGUILayout.LabelField(new GUIContent(platform), networkWidthOption);
            EditorGUILayout.LabelField(new GUIContent(currentVersion), versionWidthOption);
            GUILayout.Space(3);

            if (currentVersion.Contains("beta") || currentVersion.Contains("alpha"))
            {
                return;
            }

            EditorGUILayout.LabelField(new GUIContent(latestVersion), versionWidthOption);
            GUILayout.Space(3);

            bool needsUpgrade = Yodo1AdNetworkUtil.CompareVersions(currentVersion, latestVersion) == -1;
            GUI.enabled = needsUpgrade;
            if (GUILayout.Button(new GUIContent("Upgrade"), fieldWidth))
            {
                UpgradeButtonClicked();
            }
            GUI.enabled = true;
        }
        GUILayout.Space(4);
    }

    private void DrawNetworkDetailRow(Yodo1AdNetwork adNetwork)
    {
        using (new EditorGUILayout.HorizontalScope())
        {
            GUILayout.Space(5);
            EditorGUILayout.LabelField(new GUIContent(GetDisplayName(adNetwork)), versionWidthOption);
            EditorGUILayout.LabelField(new GUIContent(adNetwork.version), versionWidthOption);
            GUILayout.Space(3);
            DrawNetworkActionButton(adNetwork);
            GUILayout.Space(3);
        }
        GUILayout.Space(15);
    }

    private void DrawNetworkActionButton(Yodo1AdNetwork adNetwork)
    {
        bool isProtected = adNetwork.name.IndexOf("APPLOVIN", StringComparison.OrdinalIgnoreCase) >= 0
                        || adNetwork.name.IndexOf("ADMOB", StringComparison.OrdinalIgnoreCase) >= 0
                        || adNetwork.name.IndexOf("AMAZON", StringComparison.OrdinalIgnoreCase) >= 0;

        if (isProtected)
        {
            GUI.enabled = false;
            GUILayout.Button(new GUIContent("Remove"), fieldWidth);
            GUI.enabled = true;
            return;
        }

        if (Yodo1AdNetworkEditorAvailability.IsNetworkUnavailableInIntegrationManagerUi(platformTabSelected != 0, adNetwork))
        {
            Yodo1AdNetworkEditorAvailability.TryGetNetworkBlockReasonForIntegrationManagerUi(platformTabSelected != 0, adNetwork, out string blockReason);
            string blockTooltip = string.IsNullOrEmpty(blockReason)
                ? "Not available in Integration Manager for this editor."
                : blockReason;

            // IMGUI does not reliably show tooltips when GUI.enabled is false; keep the control enabled and ignore clicks.
            if (GUILayout.Button(new GUIContent("N/A", blockTooltip), fieldWidth))
            {
            }

            return;
        }

        if (IsNetworkInstalled(adNetwork))
        {
            if (GUILayout.Button(new GUIContent("Remove"), fieldWidth))
            {
                string displayName = GetDisplayName(adNetwork);
                bool keepNetwork = EditorUtility.DisplayDialog(
                    "Remove " + displayName,
                    "Are you sure you want to remove " + displayName + "? This will impact REVENUE.",
                    "Do Not Remove",
                    "Remove");
                if (!keepNetwork)
                {
                    RemoveAdNetwork(adNetwork);
                }
            }
        }
        else
        {
            if (GUILayout.Button(new GUIContent("Install"), fieldWidth))
            {
                InstallAdNetwork(adNetwork);
            }
            if (installIcon != null)
            {
                GUILayout.Label(new GUIContent(installIcon), contentLabelStyle, GUILayout.Width(25f));
            }
        }
    }

    private string GetDisplayName(Yodo1AdNetwork adNetwork)
    {
        return Yodo1AdNetworkEditorAvailability.GetNetworkListDisplayName(adNetwork);
    }

    private void DrawHeaders()
    {
        using (new EditorGUILayout.HorizontalScope())
        {
            GUILayout.Space(5);
            EditorGUILayout.LabelField("Type", headerLabelStyle, networkWidthOption);
            EditorGUILayout.LabelField("Version", headerLabelStyle, versionWidthOption);
            GUILayout.Space(3);
            EditorGUILayout.LabelField("Latest Version", headerLabelStyle, versionWidthOption);
            GUILayout.Space(3);
            GUILayout.Button("Actions", headerLabelStyle, fieldWidth);
            GUILayout.Space(5);
        }
        GUILayout.Space(4);
    }

    private void DrawHeaderNetworks()
    {
        using (new EditorGUILayout.HorizontalScope())
        {
            GUILayout.Space(5);
            EditorGUILayout.LabelField("Network", headerLabelStyle, versionWidthOption);
            EditorGUILayout.LabelField("Version", headerLabelStyle, versionWidthOption);
            GUILayout.Space(3);
            GUILayout.Button("Actions", headerLabelStyle, fieldWidth);
            GUILayout.Space(5);
        }
        GUILayout.Space(4);
    }

    #endregion
}
