using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;

namespace AlterchaseSDK
{
    public class ModLoader : MonoBehaviour
    {
        private static ModLoader instance;
        private Dictionary<AlterchaseBarcode, ModPackage> loadedPackages = new Dictionary<AlterchaseBarcode, ModPackage>();
        private Dictionary<AlterchaseBarcode, ModAsset> loadedAssets = new Dictionary<AlterchaseBarcode, ModAsset>();

        [Header("Player Settings (For Testing)")]
        [SerializeField] private GameObject playerPrefab;
        private GameObject spawnedPlayer;

        private const string PLAYER_PREFAB_PATH = "AlterchaseGameData/Player/AlterchaseModPlayer";

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

        private void Awake()
        {
            if (instance != null && instance != this)
            {
                Destroy(gameObject);
                return;
            }
            instance = this;
            DontDestroyOnLoad(gameObject);
            
            SceneManager.sceneLoaded += OnSceneLoaded;
            
            LoadPlayerPrefab();
        }

        private void Start()
        {
            SpawnPlayerAtSpawnReference();
        }

        private void OnDestroy()
        {
            SceneManager.sceneLoaded -= OnSceneLoaded;
        }

        private void LoadPlayerPrefab()
        {
            if (playerPrefab == null)
            {
                GameObject loadedPrefab = Resources.Load<GameObject>(PLAYER_PREFAB_PATH);
                if (loadedPrefab != null)
                {
                    playerPrefab = loadedPrefab;
                    Debug.Log($"Loaded player prefab from Resources: {PLAYER_PREFAB_PATH}");
                }
                else
                {
                    Debug.LogWarning($"Player prefab not found at Resources/{PLAYER_PREFAB_PATH}. Trying direct asset path...");
                    
#if UNITY_EDITOR
                    playerPrefab = UnityEditor.AssetDatabase.LoadAssetAtPath<GameObject>("Assets/AlterchaseGameData/Player/AlterchaseModPlayer.prefab");
                    
                    if (playerPrefab != null)
                    {
                        Debug.Log("Loaded player prefab from AssetDatabase (Editor only)");
                    }
                    else
                    {
                        Debug.LogError("Player prefab 'AlterchaseModPlayer' not found. Assign it manually in the ModLoader component.");
                    }
#else
                    Debug.LogError("Player prefab 'AlterchaseModPlayer' not found. Assign it manually in the ModLoader component.");
#endif
                }
            }
        }

        private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
        {
            SpawnPlayerAtSpawnReference();
        }

        private void SpawnPlayerAtSpawnReference()
        {
            PlayerSpawnReference spawnRef = PlayerSpawnReference.FindSpawnReference();

            if (spawnRef == null)
            {
                Debug.LogWarning("No PlayerSpawnReference found in the scene. Player will not be spawned.");
                return;
            }

            if (playerPrefab == null)
            {
                Debug.LogError("Player prefab 'AlterchaseModPlayer' is not assigned. Cannot spawn player.");
                return;
            }

            if (spawnedPlayer != null)
            {
                Destroy(spawnedPlayer);
            }

            spawnedPlayer = Instantiate(playerPrefab, spawnRef.SpawnPosition, spawnRef.SpawnRotation);
            Debug.Log($"Player spawned at {spawnRef.SpawnPosition} with rotation {spawnRef.SpawnRotation.eulerAngles}");
        }

        public void SetPlayerPrefab(GameObject prefab)
        {
            playerPrefab = prefab;
            Debug.Log($"Player prefab manually set to: {prefab.name}");
        }

        public GameObject GetSpawnedPlayer()
        {
            return spawnedPlayer;
        }

        public bool LoadModPackage(ModPackage package)
        {
            if (package == null)
            {
                Debug.LogError("Cannot load null mod package.");
                return false;
            }

            if (loadedPackages.ContainsKey(package.PackageID))
            {
                Debug.LogWarning($"Mod package '{package.PackageName}' is already loaded.");
                return false;
            }

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

            loadedPackages.Add(package.PackageID, package);

            foreach (var asset in package.GetAllAssets())
            {
                if (asset != null && !loadedAssets.ContainsKey(asset.AssetID))
                {
                    loadedAssets.Add(asset.AssetID, asset);
                }
            }

            Debug.Log($"Successfully loaded mod package: {package.PackageName} (Version {package.Version})");
            return true;
        }

        public void UnloadModPackage(AlterchaseBarcode packageID)
        {
            if (loadedPackages.TryGetValue(packageID, out ModPackage package))
            {
                foreach (var asset in package.GetAllAssets())
                {
                    if (asset != null)
                    {
                        loadedAssets.Remove(asset.AssetID);
                    }
                }
                loadedPackages.Remove(packageID);
                Debug.Log($"Unloaded mod package: {package.PackageName}");
            }
        }

        public T GetAsset<T>(AlterchaseBarcode assetID) where T : ModAsset
        {
            if (loadedAssets.TryGetValue(assetID, out ModAsset asset))
            {
                return asset as T;
            }
            return null;
        }

        public List<T> GetAllAssetsOfType<T>() where T : ModAsset
        {
            List<T> results = new List<T>();
            foreach (var asset in loadedAssets.Values)
            {
                if (asset is T typedAsset)
                {
                    results.Add(typedAsset);
                }
            }
            return results;
        }

        public List<ModPackage> GetAllLoadedPackages()
        {
            return new List<ModPackage>(loadedPackages.Values);
        }

        public void LoadLevel(LevelModAsset levelAsset)
        {
            if (levelAsset == null)
            {
                Debug.LogError("Cannot load null level asset.");
                return;
            }

            if (!levelAsset.ValidateAsset(out string error))
            {
                Debug.LogError($"Level validation failed: {error}");
                return;
            }

            string sceneName = System.IO.Path.GetFileNameWithoutExtension(levelAsset.ScenePath);
            SceneManager.LoadScene(sceneName, LoadSceneMode.Single);
        }

        public GameObject SpawnModel(ModelModAsset modelAsset, Vector3 position, Quaternion rotation)
        {
            if (modelAsset == null || modelAsset.ModelPrefab == null)
            {
                Debug.LogError("Cannot spawn null model asset or prefab.");
                return null;
            }

            return Instantiate(modelAsset.ModelPrefab, position, rotation);
        }

        public GameObject SpawnEnemy(EnemyModAsset enemyAsset, Vector3 position, Quaternion rotation)
        {
            if (enemyAsset == null || enemyAsset.EnemyPrefab == null)
            {
                Debug.LogError("Cannot spawn null enemy asset or prefab.");
                return null;
            }

            return Instantiate(enemyAsset.EnemyPrefab, position, rotation);
        }
    }
}
