using System.IO;
using System.Linq;
using TMPro;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.UI;


namespace IngameReveries
{
    // ModBehaviour will be instantiated and attached as a component in a container game object named <Your Mod ID>
    // Multiple ModBehaviours in your mod will share the same container.
    public class IngameReveries : ModBehaviour
    {
        private GameObject _ingameReveriesUI;

        private AssetBundle _reveriesBundle;
        private GameObject _reveriesPrefab;

        private void Awake()
        {
            // Metadata of your mod is stored in this.about
            Debug.Log("Hello! I'm loaded! " + mod.metadata.id);

            // If you need to patch with Harmony, you can use this.harmony to access the Harmony instance for your mod.
            // It will be created with your mod's id automatically, the first time you access the property.
            harmony.PatchAll();
        }

        private void Start()
        {
            InitializeAssets();

            SceneManager.sceneLoaded += OnSceneLoaded;
        }

        private void OnDestroy()
        {
            // Make sure you clean up properly to support Live Reload.
            Debug.Log("Good bye! " + mod.metadata.id);
            harmony.UnpatchAll();
            
            SceneManager.sceneLoaded -= OnSceneLoaded;
        }
        
        private void OnSceneLoaded(Scene scene, LoadSceneMode mode)
        {
            // Check if UI already instantiated
            if (_ingameReveriesUI != null)
            {
                return;
            }

            string gameSceneDir = "Assets/Dew/Zones/";
            string relativeToScene = Path.GetRelativePath(gameSceneDir, scene.path);

            if (!relativeToScene.StartsWith(".."))
            {
                Debug.Log($"[IngameReveries] Switched to scene inside {gameSceneDir}");

                GameObject menuViewGO = GameObject.Find("GameLogicPackage/UI/InGame/UI_Common_MenuView");
                if (menuViewGO == null)
                {
                    Debug.Log("Couldn't find menu view");
                    return;
                }

                _ingameReveriesUI = Instantiate(_reveriesPrefab, menuViewGO.transform);
                _ingameReveriesUI.SetActive(true);
                _ingameReveriesUI.name = "IngameReveriesUI";
                _ingameReveriesUI.transform.SetSiblingIndex(1);

                var reveries = _ingameReveriesUI.GetComponent<UI_Reveries>();

                // Show reveries window
                var canvasGroup = _ingameReveriesUI.GetComponent<CanvasGroup>();
                canvasGroup.alpha = 1f;
                canvasGroup.interactable = true;
                canvasGroup.blocksRaycasts = true;
                    
                // Position reveries window top left
                var rect = _ingameReveriesUI.GetComponent<RectTransform>();
                rect.anchorMin = new Vector2(0f, 1f);
                rect.anchorMax = new Vector2(0f, 1f);
                rect.pivot = new Vector2(0f, 1f);
                rect.anchoredPosition = new Vector2(+70f, -400f);
                    
                FixFonts();
            }
        }

        private void InitializeAssets()
        {
            string bundlePath = Path.Combine(mod.path, "assets", "bundle");

            if (!File.Exists(bundlePath))
            {
                Debug.LogError($"[IngameReveries] Bundle not found at: {bundlePath}");
                return;
            }

            _reveriesBundle = AssetBundle.GetAllLoadedAssetBundles()
                .FirstOrDefault(b => b.name == "logosteal" || b.mainAsset != null);

            if (_reveriesBundle == null)
            {
                // If it isn't loaded yet, load it from disk
                Debug.Log("[IngameReveries] Loading Bundle");
                _reveriesBundle = AssetBundle.LoadFromFile(bundlePath);
            }
            else
            {
                Debug.Log("[IngameReveries] Bundle already loaded");
            }

            if (_reveriesBundle == null)
            {
                Debug.LogError("[IngameReveries] Failed to load AssetBundle!");
                return;
            }

            // Load the prefab from the bundle
            string assetName = _reveriesBundle.GetAllAssetNames().First();
            _reveriesPrefab = _reveriesBundle.LoadAsset<GameObject>(assetName);

            if (_reveriesPrefab == null)
            {
                Debug.LogError("[IngameReveries] Failed to load prefab!");

                // List what's in the bundle for debugging
                string[] assetNames = _reveriesBundle.GetAllAssetNames();
                Debug.Log("[IngameReveries] Assets in bundle:");
                foreach (string name in assetNames)
                {
                    Debug.Log($"  - {name}");
                }

                return;
            }

            Debug.Log("[IngameReveries] Successfully loaded prefab!");
        }

        private void FixFonts()
        {
            // Get all fonts
            TMP_FontAsset[] loadedFonts = Resources.FindObjectsOfTypeAll<TMP_FontAsset>();

            // Get all text from the reveries window
            TMP_Text[] textComponents = _ingameReveriesUI.GetComponentsInChildren<TMP_Text>(true);
            foreach (TMP_Text textComp in textComponents)
            {
                if (textComp.font == null) continue;

                string originalFontName = textComp.font.name;

                // Match the font by name, ensuring we don't pick the dead assetbundle version
                foreach (TMP_FontAsset loadedFont in loadedFonts)
                {
                    // Pick a matching font that has an active atlas/material
                    if (loadedFont.name == originalFontName && loadedFont.atlasTexture != null)
                    {
                        textComp.font = loadedFont;
                
                        // Force TMP to update its internal mesh and material reference
                        textComp.ForceMeshUpdate();
                        textComp.SetAllDirty();
                        break;
                    }
                }
            }
        }
    }
}