#if MODIO_INSTALLED
using ModIO;
#endif

using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using UnityEngine;

namespace AlterchaseSDK
{
    public class ModIOIntegration : MonoBehaviour
    {
        private static ModIOIntegration instance;
        private bool isInitialized = false;
        private bool isAuthenticated = false;

        public static ModIOIntegration Instance
        {
            get
            {
                if (instance == null)
                {
                    GameObject go = new GameObject("ModIOIntegration");
                    instance = go.AddComponent<ModIOIntegration>();
                    DontDestroyOnLoad(go);
                }
                return instance;
            }
        }

        public bool IsInitialized => isInitialized;
        public bool IsAuthenticated => isAuthenticated;

        public event Action OnInitialized;
        public event Action OnAuthenticationSuccess;
        public event Action<string> OnAuthenticationFailed;

        private void Awake()
        {
            if (instance != null && instance != this)
            {
                Destroy(gameObject);
                return;
            }
            instance = this;
            DontDestroyOnLoad(gameObject);
        }

        private void Start()
        {
            InitializeModIO();
        }

        public void InitializeModIO()
        {
#if MODIO_INSTALLED
            Result result = ModIOUnity.InitializeForUser("default");
            
            if (!result.Succeeded())
            {
                Debug.LogError($"mod.io initialization failed: {result.message}");
                return;
            }

            isInitialized = true;
            Debug.Log("mod.io plugin initialized successfully!");
            OnInitialized?.Invoke();
            CheckAuthentication();
#else
            Debug.LogWarning("mod.io SDK not installed. Please install the mod.io Unity plugin and add MODIO_INSTALLED to Scripting Define Symbols.");
            isInitialized = false;
#endif
        }

        private async void CheckAuthentication()
        {
#if MODIO_INSTALLED
            Result result = await ModIOUnityAsync.IsAuthenticated();
            
            if (result.Succeeded())
            {
                isAuthenticated = true;
                OnAuthenticationSuccess?.Invoke();
                Debug.Log("User is already authenticated.");
            }
#else
            await Task.CompletedTask;
#endif
        }

        public async Task<bool> AuthenticateWithEmail(string email)
        {
            if (!isInitialized)
            {
                Debug.LogError("mod.io not initialized. Call InitializeModIO() first.");
                return false;
            }

#if MODIO_INSTALLED
            Result result = await ModIOUnityAsync.RequestAuthenticationEmail(email);
            
            if (!result.Succeeded())
            {
                string error = $"Failed to request authentication email: {result.message}";
                Debug.LogError(error);
                OnAuthenticationFailed?.Invoke(error);
                return false;
            }

            Debug.Log($"Authentication email sent to: {email}");
            return true;
#else
            Debug.LogError("mod.io SDK not installed.");
            await Task.CompletedTask;
            return false;
#endif
        }

        public async Task<bool> SubmitSecurityCode(string code)
        {
            if (!isInitialized)
            {
                Debug.LogError("mod.io not initialized.");
                return false;
            }

#if MODIO_INSTALLED
            Result result = await ModIOUnityAsync.SubmitEmailSecurityCode(code);
            
            if (!result.Succeeded())
            {
                string error = $"Failed to submit security code: {result.message}";
                Debug.LogError(error);
                OnAuthenticationFailed?.Invoke(error);
                return false;
            }

            isAuthenticated = true;
            OnAuthenticationSuccess?.Invoke();
            
            ResultAnd<User> userResult = await ModIOUnityAsync.GetCurrentUser();
            if (userResult.result.Succeeded())
            {
                Debug.Log($"Authenticated as: {userResult.value.username}");
            }

            return true;
#else
            Debug.LogError("mod.io SDK not installed.");
            await Task.CompletedTask;
            return false;
#endif
        }

        public async Task<ModIOModProfile[]> BrowseMods(ModIOSearchFilter filter = null)
        {
            if (!isInitialized)
            {
                Debug.LogError("mod.io not initialized.");
                return Array.Empty<ModIOModProfile>();
            }

            if (filter == null)
            {
                filter = new ModIOSearchFilter();
            }

#if MODIO_INSTALLED
            ResultAnd<ModPage> result = await ModIOUnityAsync.GetMods(filter);
            
            if (!result.result.Succeeded())
            {
                Debug.LogError($"Failed to browse mods: {result.result.message}");
                return Array.Empty<ModIOModProfile>();
            }

            Debug.Log($"Found {result.value.modProfiles.Length} mods");
            
            ModIOModProfile[] profiles = new ModIOModProfile[result.value.modProfiles.Length];
            for (int i = 0; i < result.value.modProfiles.Length; i++)
            {
                profiles[i] = new ModIOModProfile
                {
                    id = result.value.modProfiles[i].id,
                    name = result.value.modProfiles[i].name,
                    summary = result.value.modProfiles[i].summary
                };
            }
            return profiles;
#else
            await Task.CompletedTask;
            return Array.Empty<ModIOModProfile>();
#endif
        }

        public async Task<bool> SubscribeToMod(long modId)
        {
            if (!isAuthenticated)
            {
                Debug.LogError("User must be authenticated to subscribe to mods.");
                return false;
            }

#if MODIO_INSTALLED
            Result result = await ModIOUnityAsync.SubscribeToMod(modId);
            
            if (!result.Succeeded())
            {
                Debug.LogError($"Failed to subscribe to mod: {result.message}");
                return false;
            }

            Debug.Log($"Successfully subscribed to mod ID: {modId}");
            return true;
#else
            await Task.CompletedTask;
            Debug.LogError("mod.io SDK not installed.");
            return false;
#endif
        }

        public async Task<bool> UnsubscribeFromMod(long modId)
        {
            if (!isAuthenticated)
            {
                Debug.LogError("User must be authenticated to unsubscribe from mods.");
                return false;
            }

#if MODIO_INSTALLED
            Result result = await ModIOUnityAsync.UnsubscribeFromMod(modId);
            
            if (!result.Succeeded())
            {
                Debug.LogError($"Failed to unsubscribe from mod: {result.message}");
                return false;
            }

            Debug.Log($"Successfully unsubscribed from mod ID: {modId}");
            return true;
#else
            await Task.CompletedTask;
            Debug.LogError("mod.io SDK not installed.");
            return false;
#endif
        }

        public async Task<bool> UploadModPackage(ModPackage package, string modDirectory)
        {
            if (!isAuthenticated)
            {
                Debug.LogError("User must be authenticated to upload mods.");
                return false;
            }

            if (!package.ValidatePackage(out List<string> errors))
            {
                Debug.LogError($"Package validation failed:\n{string.Join("\n", errors)}");
                return false;
            }

#if MODIO_INSTALLED
            ModProfileDetails details = new ModProfileDetails
            {
                name = package.PackageName,
                summary = package.Description,
                logo = package.PackageIcon
            };

            ResultAnd<long> createResult = await ModIOUnityAsync.CreateModProfile(ModIOUnity.GenerateCreationToken(), details);
            
            if (!createResult.result.Succeeded())
            {
                Debug.LogError($"Failed to create mod profile: {createResult.result.message}");
                return false;
            }

            long modId = createResult.value;

            ModfileDetails modFile = new ModfileDetails
            {
                modId = modId,
                directory = modDirectory
            };

            Task uploadTask = ModIOUnityAsync.UploadModfile(modFile);
            
            while (!uploadTask.IsCompleted)
            {
                await Task.Yield();
            }

            if (uploadTask.IsFaulted)
            {
                Debug.LogError($"Failed to upload mod file: {uploadTask.Exception}");
                return false;
            }

            Debug.Log($"Successfully uploaded mod package: {package.PackageName}");
            return true;
#else
            await Task.CompletedTask;
            Debug.LogError("mod.io SDK not installed.");
            return false;
#endif
        }

        public ModIOModProfile[] GetSubscribedMods()
        {
            if (!isAuthenticated)
            {
                Debug.LogWarning("User is not authenticated.");
                return Array.Empty<ModIOModProfile>();
            }

#if MODIO_INSTALLED
            SubscribedMod[] subscribedMods = ModIOUnity.GetSubscribedMods(out Result result);
            
            if (!result.Succeeded())
            {
                Debug.LogError($"Failed to get subscribed mods: {result.message}");
                return Array.Empty<ModIOModProfile>();
            }

            ModIOModProfile[] profiles = new ModIOModProfile[subscribedMods.Length];
            for (int i = 0; i < subscribedMods.Length; i++)
            {
                profiles[i] = new ModIOModProfile
                {
                    id = subscribedMods[i].modProfile.id,
                    name = subscribedMods[i].modProfile.name,
                    summary = subscribedMods[i].modProfile.summary
                };
            }
            return profiles;
#else
            Debug.LogError("mod.io SDK not installed.");
            return Array.Empty<ModIOModProfile>();
#endif
        }

        public async Task<Texture2D> DownloadModLogo(long modId)
        {
#if MODIO_INSTALLED
            ResultAnd<Texture2D> result = await ModIOUnityAsync.DownloadTexture(modId);
            
            if (!result.result.Succeeded())
            {
                Debug.LogError($"Failed to download mod logo: {result.result.message}");
                return null;
            }

            return result.value;
#else
            await Task.CompletedTask;
            return null;
#endif
        }
    }

    [Serializable]
    public class ModIOModProfile
    {
        public long id;
        public string name;
        public string summary;
    }

    [Serializable]
    public class ModIOSearchFilter
    {
#if MODIO_INSTALLED
        private SearchFilter internalFilter;

        public ModIOSearchFilter()
        {
            internalFilter = new SearchFilter();
        }

        public void SetSearchPhrase(string phrase)
        {
            internalFilter.SetSearchPhrase(phrase);
        }

        public static implicit operator SearchFilter(ModIOSearchFilter filter)
        {
            return filter?.internalFilter ?? new SearchFilter();
        }
#else
        public void SetSearchPhrase(string phrase)
        {
        }
#endif
    }
}
