
using System.Linq;
using TMPro;
using UnityEngine;
using azixMcAze.SerializableDictionary;
using UnityEditor;

namespace Gyvr.Mythril2D
{

    public class UISkills : AUIMenu
    {
        [Header("References")]
        [SerializeField] private GameObject m_skillListEntryPrefab = null;
        [SerializeField] private GameObject m_skillListRoot = null;
        [SerializeField] private TextMeshProUGUI m_skillPoints = null;
        [SerializeField] private SerializableDictionary<ESkillCategory, UISkillCategory> m_categories = null;

        [Header("Settings")]
        [SerializeField] private ESkillCategory m_initialCategory = ESkillCategory.Magic;

        [Header("Dialogues")]
        [SerializeField] private DialogueSequence m_cannotLearnBecauseRequeriments = null;
        [SerializeField] private DialogueSequence m_cannotLearnBecausePoints = null;
        [SerializeField] private DialogueSequence m_cannotLearnBecauseAlreadyLearned = null;
        [SerializeField] private DialogueSequence m_learnSucceeded = null;

        [Header("Audio")]
        [SerializeField] private AudioClipResolver m_learnAudio;

        private UISkillListEntry[] m_entries = null;
        private Hero m_character => GameManager.Player;


        private int m_availablePoints = 0;

        protected override void OnInit()
        {
            foreach (var category in m_categories)
            {
                category.Value.SetCategory(category.Key);
            }
        }
        protected override void OnMenuShown(params object[] args)
        {
            Debug.Assert(args.Length == 0, "Skills menu invoked with incorrect arguments");
            SelectCategory(m_initialCategory);
            UpdateUI();
        }
        private void UpdateUI()
        {
            m_availablePoints = m_character.availablePoints;
            m_skillPoints.text = m_availablePoints.ToString();

            foreach (UISkillListEntry entry in m_entries)
            {
                entry.UpdateUI();
            }
        }

        public override GameObject FindSomethingToSelect()
        {
            if (m_entries.Length > 0)
            {
                return m_entries[0].gameObject;
            }

            return base.FindSomethingToSelect();
        }


        private void ClearSkillList()
        {
            for (int i = 0; i < m_skillListRoot.transform.childCount; ++i)
            {
                Transform child = m_skillListRoot.transform.GetChild(i);
                Destroy(child.gameObject);
            }
        }

        private void FillSkillList(ESkillCategory type)
        {
            string[] guids = AssetDatabase.FindAssets("t:Skill", new[] { "Assets/Mythril2D/Demo/Database/Skills" });
            Skill[] skills = guids
                .Select(guid => AssetDatabase.LoadAssetAtPath<Skill>(AssetDatabase.GUIDToAssetPath(guid)))
                .Where(skill => skill != null && skill.category== type)
                .ToArray();

            m_entries = new UISkillListEntry[skills.Length];

            for (int i = 0; i < skills.Length; ++i)
            {
                Skill skill = skills[i];

                GameObject entryInstance = Instantiate(m_skillListEntryPrefab, m_skillListRoot.transform);
                UISkillListEntry entry = entryInstance.GetComponent<UISkillListEntry>();

                if (entry)
                {
                    entry.Initialize(skill, type);
                    m_entries[i] = entry;
                }
            }
        }


        // Select an skill from the list
        private void OnSkillSelectedFromList(Skill skill) => OnSkillClicked(skill);

        private void OnSkillCategorySelected(ESkillCategory type) => SelectCategory(type);

        private void SelectCategory(ESkillCategory category)
        {
            foreach (var entry in m_categories)
            {
                entry.Value.SetHighlight(false);
            }

            m_categories[category].SetHighlight(true);

            ClearSkillList();
            FillSkillList(category);
        }

        private async void OnSkillClicked(Skill skill)
        {
            if (skill.IsValid(out bool hasPoints, out string[] missingRequiments, out bool notLearned))
            {
                await GameManager.DialogueSystem.Main.PlayNow(DialogueUtils.CreateDialogueTree(m_learnSucceeded, null, skill.displayName, skill.description));
                GameManager.NotificationSystem.audioPlaybackRequested.Invoke(m_learnAudio);

                skill.Learn();
                m_character.LogUsedPoints(skill.cost);
                UpdateUI();
            }
            else if (!notLearned)
            {
                await GameManager.DialogueSystem.Main.PlayNow(DialogueUtils.CreateDialogueTree(m_cannotLearnBecauseAlreadyLearned, null, skill.displayName));
            }
            else if (!hasPoints)
            {
                await GameManager.DialogueSystem.Main.PlayNow(DialogueUtils.CreateDialogueTree(m_cannotLearnBecausePoints, null, skill.cost.ToString(), skill.displayName));
            }
            else if (missingRequiments.Length>0)
            {
                await GameManager.DialogueSystem.Main.PlayNow(DialogueUtils.CreateDialogueTree(m_cannotLearnBecauseRequeriments, null, skill.displayName, skill.GenerateInlineDescription(missingRequiments)));
            }
        }
    }
}
