﻿using System;
using System.Collections;
using System.Collections.Generic;
using System.Collections.Specialized;
using UnityEngine;
using UnityEngine.UI;
using UnityEditor;


namespace BattleRoyale.Spells
{
    /// <summary>
    /// Singleton that holds a catalog of spell prefab associations for quick reference at runtime
    /// </summary>
    [Serializable]
    public class SpellCatalog : MonoBehaviour
    {
        [SerializeField] public IconColors IconColors;
        [SerializeField] public SpellCollection SpellCollection;

        // PRIVATE MEMBERS //

        private static SpellCatalog m_instance = null;
        
        private void Start()
        {
            if (m_instance == null)
                m_instance = this;
            else if (m_instance != this)
                DestroyImmediate(gameObject);
        }

        /// <summary>
        /// Returns the spell catalog of the active scene
        /// </summary>
        /// <returns></returns>
        public static SpellCatalog GetCatalog()
        {
            return m_instance;
        }
        
        /// <summary>
        /// Returns true if the catalog contains at least one valid spell
        /// </summary>
        /// <returns></returns>
        public bool ContainsSpells()
        {
            // If we are missing our spell collection scriptable, return false
            if (!SpellCollection)
                return false;

            // Return the spell collection check value
            return SpellCollection.ContainsSpells();
        }

        /// <summary>
        /// Returns true if the catalog contains a spell of the given type.
        /// </summary>
        /// <param name="_type"></param>
        /// <returns></returns>
        public bool ContainsSpellOfType(SpellType _type)
        {
            // If we don't have a collection, return null
            if (!SpellCollection)
                return false;

            // If the given subtype values do not have a matching subtype, return null
            if (!SpellType.IsValidType(_type))
                return false;

            // Search the spell collection for a spell by that type and return
            return SpellCollection.ContainsSpellOfType(_type);
        }
        public bool ContainsSpellOfType(SpellPrimaryType _primary, SpellSecondaryType _secondary)
        {
            // If we don't have a collection, return null
            if (!SpellCollection)
                return false;

            // If the given subtype values do not have a matching subtype, return null
            if (!SpellType.IsValidType(_primary, _secondary))
                return false;

            // Search the spell collection for a spell by that type and return
            return SpellCollection.ContainsSpellOfType(new SpellType(_primary, _secondary));
        }
        
        /// <summary>
        /// Returns a random spell type that can be found in the catalog
        /// </summary>
        /// <returns></returns>
        public SpellType GetRandomValidType()
        {
            // If we don't have a collection, return the default type
            if (!SpellCollection)
                return default(SpellType);

            // Otherwise, get a random type from the collection
            return SpellCollection.GetRandomValidType();
        }
        /// <summary>
        /// Returns a random spell from our spell list
        /// </summary>
        /// <returns></returns>
        public Spell GetRandomSpell()
        {
            // If we don't have a collection, return null
            if (!SpellCollection)
                return null;
            
            // Otherwise, get a random spell from the collection
            return SpellCollection.GetRandomSpell();
        }

        /// <summary>
        /// Retrieves a spell from the catalog given a Spell Type.
        /// </summary>
        /// <param name="_type"></param>
        /// <returns></returns>
        public Spell GetSpellOfType(SpellType _type)
        {
            // If we don't have a collection, return null
            if (!SpellCollection)
                return null;

            // Get the spell type from the Collection
            Spell _spell = SpellCollection.GetSpellOfType(_type);

            // Return the value from our spell library of the given type
            return _spell;
        }
        public Spell GetSpellOfType(SpellPrimaryType _spellPrimaryType, SpellSecondaryType _spellSecondaryType)
        {
            // If we don't have a collection, return null
            if (!SpellCollection)
                return null;

            // If the given subtype values do not have a matching type, return null
            if (!SpellType.IsValidType(_spellPrimaryType, _spellSecondaryType))
                return null;

            // Merge the subtypes into a single type
            SpellType _type = new SpellType(_spellPrimaryType, _spellSecondaryType);
            
            // Return the value from our spell library of the given type
            return SpellCollection.GetSpellOfType(_type);
        }
        public Spell GetSpellOfType(int _spellPrimaryType, int _spellSecondaryType)
        {
            // Integers are being used here in place of enums to assist with Photon spell calls.

            // If we don't have a collection, return null
            if (!SpellCollection)
                return null;

            // If the given subtype values do not have a matching type, return null
            if (!SpellType.IsValidType(_spellPrimaryType, _spellSecondaryType))
                return null;

            // Construct the serialized spell type
            SpellType _type = new SpellType((SpellPrimaryType)_spellPrimaryType, (SpellSecondaryType)_spellSecondaryType);

            // Return the value from our spell library of the given type
            return SpellCollection.GetSpellOfType(_type);
        }
    }
    
    #if UNITY_EDITOR // This stops this bit of code from ending up in the compiled build of the game.
    [CustomEditor(typeof(SpellCatalog)), CanEditMultipleObjects]
    public class SpellCatalogEditor : Editor
    {
        public override void OnInspectorGUI()
        {
            EditorGUILayout.BeginHorizontal();

            EditorGUILayout.BeginVertical();

            SpellCatalog spellCatalog = target as SpellCatalog;

            spellCatalog.IconColors = (IconColors)EditorGUILayout.ObjectField(spellCatalog.IconColors, typeof(IconColors), false);
            spellCatalog.SpellCollection = (SpellCollection)EditorGUILayout.ObjectField(spellCatalog.SpellCollection, typeof(SpellCollection), false);

            if (GUI.changed)
                EditorUtility.SetDirty(spellCatalog.SpellCollection);

            if (!spellCatalog.SpellCollection)
            {
                EditorGUILayout.LabelField("Spell Catalog: Catalog is empty!");
                EditorGUILayout.LabelField("Please load a SpellCollection into the catalog.");
                
                return;
            }
            else
            {
                // For each primary type...
                for (int p = 0; p < Enum.GetValues(typeof(SpellPrimaryType)).Length; p++)
                {
                    //Debug.Log(Enum.GetName(typeof(SpellPrimaryType), (SpellPrimaryType)p));

                    // Space
                    EditorGUILayout.LabelField("");

                    // Begin a box to hold our Primary Type spells
                    EditorGUILayout.BeginVertical("HelpBox");
                
                    EditorGUILayout.BeginHorizontal("Box");

                    // Print out the primary name of this spell category.
                    EditorGUILayout.LabelField(Enum.GetName(typeof(SpellPrimaryType), (SpellPrimaryType)p) + " Spells");

                    EditorGUILayout.EndHorizontal();

                    EditorGUILayout.BeginVertical();

                    // Tracks how many spells of this primary type are in our catalog
                    int _numTypeSpells = 0;

                    // For each secondary type...
                    for (int s = 0; s < Enum.GetValues(typeof(SpellSecondaryType)).Length; s++)
                    {
                        if (!spellCatalog.ContainsSpellOfType(new SpellType((SpellPrimaryType)p, (SpellSecondaryType)s)))
                            continue;

                        // Get the spell from the catalog
                        Spell _spell = spellCatalog.GetSpellOfType((SpellPrimaryType)p, (SpellSecondaryType)s);

                        // If there is no spell in this category, continue
                        if (!_spell)
                            continue;
                        
                        // If there is no prefab in the spell, continue
                        if (!_spell.SpellPrefab)
                            continue;

                        // If there are no spell stats or the ones that are loaded are default, continue
                        if (!_spell.Stats || _spell.Stats == default(SpellStats))
                            continue;

                        // Begin a nested box to hold our spell
                        EditorGUILayout.BeginVertical("HelpBox");

                        // List our primary and secondary type
                        EditorGUILayout.LabelField("Subtype: " + Enum.GetName(typeof(SpellSecondaryType), (SpellSecondaryType)s));
                        EditorGUILayout.LabelField("Name: " + (_spell.Name == "" ? _spell.SpellPrefab.name.Replace("_", " ") : _spell.Name));
                        EditorGUILayout.LabelField("Default Colors:");

                        EditorGUILayout.BeginHorizontal();

                        Color[] _colors = _spell.GetDefaultColors();

                        EditorGUILayout.ColorField(GUIContent.none, _colors[0], false, false, false, GUILayout.Width(80));

                        GUILayout.FlexibleSpace();

                        EditorGUILayout.ColorField(GUIContent.none, _colors[1], false, false, false, GUILayout.Width(80));

                        GUILayout.FlexibleSpace();

                        EditorGUILayout.ColorField(GUIContent.none, _colors[2], false, false, false, GUILayout.Width(80));

                        GUILayout.FlexibleSpace();

                        EditorGUILayout.ColorField(GUIContent.none, _colors[3], false, false, false, GUILayout.Width(80));

                        EditorGUILayout.EndHorizontal();

                        //End the nested box
                        EditorGUILayout.EndVertical();
                    
                        _numTypeSpells++;
                    }

                    // If we did not find any spells of this primary type, print a label field stating so.
                    if (_numTypeSpells == 0)
                        EditorGUILayout.LabelField("No " + Enum.GetName(typeof(SpellPrimaryType), (SpellPrimaryType)p) + " Spells found!");

                    EditorGUILayout.EndVertical();

                    // End 
                    EditorGUILayout.EndVertical();
                }

                EditorGUILayout.EndVertical();

                GUILayout.Space(8);

                EditorGUILayout.EndHorizontal();
            }
        }
    }
    #endif
}
