using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using Gyvr.Mythril2D;
using log4net.Core;
using MackySoft.SerializeReferenceExtensions;
using NUnit.Framework;
using UnityEditor.Experimental.GraphView;
using UnityEditor.Playables;
using UnityEngine;

namespace Gyvr.Mythril2D
{
    public struct SkillDescriptionLine
    {
        public string header;
        public string content;
    }

    public enum ESkillCategory
    {
        Archery,
        Swordsmanship,
        Magic,
        Necromancy,
        Smithing,
        Cooking,
        Gathering
    }

    public abstract class Skill : DatabaseEntry, INameable
    {
        [Header("UI Settings")]
        [SerializeField] private Sprite m_icon = null;
        [SerializeField] private string m_displayName = string.Empty;
        [SerializeField] private string m_description = string.Empty;

        [Header("General Settings")]
        [SerializeField] private int m_cost = 1;
        [SerializeField] private ESkillCategory m_category;
        [SerializeReference, SubclassSelector] private ISkillCondition[] m_conditions = null;



        public int cost => m_cost;
        public ESkillCategory category => m_category;
        public Sprite icon => m_icon;
        public string description => m_description;
        public string displayName => DisplayNameUtils.GetNameOrDefault(this, m_displayName);
        public bool hasConditions => m_conditions.Length > 0;

        public virtual bool IsValid(out bool hasPoints, out String[] missingRequiments, out bool notLearned)
        {
            hasPoints = GameManager.Player.availablePoints >= this.m_cost;
            List<string> missingList = new List<string>();
            notLearned = !GameManager.Player.HasSkill(this);

            if (m_conditions != null)
            {
                foreach (ISkillCondition condition in m_conditions)
                {
                    if (condition != null && !condition.IsValid(this))
                        missingList.Add(condition.GetDescriptive());
                }
            }
            missingRequiments = missingList.ToArray();
            return hasPoints && missingRequiments.Length <= 0 && notLearned;
        }

        public virtual void Learn()
        {
            GameManager.Player.AddSkill(this);
        }


        public abstract void GenerateAdditionalDescriptionLines(List<SkillDescriptionLine> lines);

        public string GenerateInlineDescription(String[] missingRequiments)
        {
            string res = "";
            for (int index = 0; index < missingRequiments.Length; index++)
            {
                string condition = missingRequiments[index];
                res += condition;
                if (index < missingRequiments.Length - 1)
                {
                    res += ", ";
                }
            }
            return res;
        }
        public string GenerateInlineDescription()
        {
            string str = "";
            for (int index = 0; index < m_conditions.Length; index++)
            {
                ISkillCondition condition = m_conditions[index];
                if (condition != null)
                {
                    str += condition.GetDescriptive();
                    if (index < m_conditions.Length - 1)
                    {
                        str += ", ";
                    }
                }
            }
            return str;
        }
    }


    public interface ISkillCondition
    {
        bool IsValid(Skill skillSheet);
        string GetDescriptive();
    }
    [Serializable]
    public class SkillCondition : ISkillCondition
    {
        public Skill skill;
        public bool IsValid(Skill skillSheet)
        {
            return GameManager.Player.HasSkill(skill);
        }

        public string GetDescriptive()
        {
            return $"{skill.displayName}";
        }
    }

    [Serializable]
    public class SkillLevelCondition : ISkillCondition
    {
        public int level;
        public bool IsValid(Skill skillSheet)
        {
            return GameManager.Player.level >= level; ; // Placeholder
        }
        public string GetDescriptive()
        {
            return $"level ({level})";
        }
    }
    [Serializable]
    public class SkillAbilityCondition : ISkillCondition
    {
        public AbilitySheet ability;
        public bool IsValid(Skill skillSheet)
        {
            return GameManager.Player.HasAbility(ability); // Placeholder
        }
        public string GetDescriptive()
        {
            return $"ability {ability.displayName}";
        }
    }
    [Serializable]
    public class SkillStatsCondition : ISkillCondition
    {
        public EStat stat;
        public int minValue;
        public bool IsValid(Skill skillSheet)
        {
            int level = GameManager.Player.stats[stat];
            return minValue<=level; // Placeholder
        }
        public string GetDescriptive()
        {
            return $" {stat} ({minValue})";
        }
    }
}
