using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using System.Linq;

public class Player : MonoBehaviour
{

    Rigidbody2D rb;
    private Animator myAnimator;
    public float walkSpeed = 4f;
    float speedLimiter = 0.7f;
    float inputHorizontal;
    float inputVertical;
    public GameObject Panel;
    private bool inRange = false;
    public ParticleSystem dmgParticleSystem;

    public HealthBar healthBar;

    private static bool attackSword;
    private bool attackFist;
    private static bool pickaxeInUse;
    private static bool playerInCollider;

    public bool lvlUp = false;
    public float test;

    private float timerRegen = 0f;
    private float timerTick = 0f;
    private float waitRegen = 8.0f;
    private float waitTick = 1.0f;

    private bool startRegen = false;

    private bool canWalk = true;

    [Header("Player Starts values")]
    public const int BaseHealth = 10;
    public const float BaseSpeed = 4f;

  
    [Header("Player Skills Points")]
    public int healthPoints;
    public int defensePoints;
    public int strengthPoints;
    public int intelligencePoints;

    [Header("Player current values")]
    public float attackValue;
    public float defenseValue;
    public float currentSpeed; // as WalkSpeed

    public float currentHealth;
    public float maxHealth;

    public float exp;
    public int lvl;
    public float maxExp;
    public LevelBar levelBar;
    public FloatValue minPlayerExp;



    public static void putPlayerInCollider()
    {
        playerInCollider = true;
    }

    public static void takePlayerFromCollider()
    {
        playerInCollider = false;
    }

    void Start()
    {
        Panel = GameObject.FindObjectsOfType<GameObject>(true).Where(sr => sr.gameObject.name == "YouDied").ToArray()[0];
        healthBar = (HealthBar)FindObjectOfType<HealthBar>();
        levelBar = (LevelBar)FindObjectOfType<LevelBar>();
        if (OnMapAppearanceMethod.IsNewGame())
        {
            currentHealth = PlayerPrefs.GetFloat("health");
            exp = PlayerPrefs.GetFloat("exp");
            lvl = PlayerPrefs.GetInt("lvl");
        }
        else
        {
            currentHealth = PlayerPrefs.GetFloat("health-S");
            exp = PlayerPrefs.GetFloat("exp-S");
            lvl = PlayerPrefs.GetInt("lvl-S");
        }
        rb = gameObject.GetComponent<Rigidbody2D>();
        myAnimator = GetComponent<Animator>();
        //healthBar.SetMaxHealth(maxHealth.initialValue);
        //healthBar.SetHealth(currentHealth);
        //levelBar.SetStartExp(minPlayerExp.initialValue);
        //levelBar.SetExp(exp);

        ManageSpeed();
        walkSpeed = PlayerPrefs.GetFloat("speed");


        ManageLevels(exp);
    }

    public void GetExp(float expValue)
    {
        exp = exp + expValue;
        ManageLevels(exp);
    }

    public void ManageLevels(float exp)
    {
        if (lvl == 1)
        {
            maxExp = 25;
            if (exp >= maxExp)
            {
                lvl = 2;
                lvlUp = true;
                maxExp = 50;

                // Add points and refresh view (if opened)
                SkillsPointsManger.Instance.AddFreePoints(2);
                SkillsPointsManger.Instance.UpdatePanelView();
            }
        }
        else if (lvl == 2)
        {
            maxExp = 50;
            if (exp >= maxExp)
            {
                lvl = 3;
                lvlUp = true;
                maxExp = 100;

                // Add points and refresh view (if opened)
                SkillsPointsManger.Instance.AddFreePoints(2);
                SkillsPointsManger.Instance.UpdatePanelView();
            }
        }
        else if (lvl == 3)
        {
            maxExp = 100;
            if (exp >= maxExp)
            {
                lvl = 4;
                lvlUp = true;
                maxExp = 200;

                // Add points and refresh view (if opened)
                SkillsPointsManger.Instance.AddFreePoints(2);
                SkillsPointsManger.Instance.UpdatePanelView();
            }
        }
        else if (lvl == 4)
        {
            maxExp = 200;
            if (exp >= maxExp)
            {
                lvl = 5;
                lvlUp = true;
                maxExp = 300;

                // Add points and refresh view (if opened)
                SkillsPointsManger.Instance.AddFreePoints(2);
                SkillsPointsManger.Instance.UpdatePanelView();
            }
        }
        else if (lvl == 5)
        {
            maxExp = 300;
            if (exp >= maxExp)
            {
                lvl = 6;
                lvlUp = true;
                maxExp = 450;

                // Add points and refresh view (if opened)
                SkillsPointsManger.Instance.AddFreePoints(2);
                SkillsPointsManger.Instance.UpdatePanelView();
            }
        }
        else if (lvl == 6)
        {
            maxExp = 450;
            if (exp >= maxExp)
            {
                lvl = 7;
                lvlUp = true;
                maxExp = 550;

                // Add points and refresh view (if opened)
                SkillsPointsManger.Instance.AddFreePoints(2);
                SkillsPointsManger.Instance.UpdatePanelView();
            }
        }
        else if (lvl == 7)
        {
            maxExp = 550;
            if (exp >= maxExp)
            {
                lvl = 8;
                lvlUp = true;
                maxExp = 700;

                // Add points and refresh view (if opened)
                SkillsPointsManger.Instance.AddFreePoints(2);
                SkillsPointsManger.Instance.UpdatePanelView();
            }
        }
    }

    public void TakeDamage(float damage, bool isPanelEnabled = true)
    {

        defensePoints = PlayerPrefs.GetInt(SkillsPointsManger.PLAYER_SKILS_DEFENSE_POINTS);

        Debug.Log($"Minion Damage: {damage}; \n\tDefense: {PlayerPrefs.GetFloat("defenseValue")}");
        
        damage = damage - PlayerPrefs.GetFloat("defenseValue");
        damage = damage < 0 ? 0 : damage;

        Debug.Log($"\tRealDamage: {damage}");

        currentHealth = PlayerPrefs.GetFloat("health");
        currentHealth = currentHealth - damage;
        PlayerPrefs.SetFloat("health", currentHealth);

        var em = dmgParticleSystem.emission;
        em.enabled = true;
        StartCoroutine(Timer());
        timerRegen = 0.0f;
        startRegen = false;
        if (currentHealth <= 0)
        {
            if (isPanelEnabled)
            {
                Panel.SetActive(true);
            }
            walkSpeed = 0f;
            canWalk = false;
        }
    }

    IEnumerator Timer()
    {
        yield return new WaitForSeconds(0.2f);
        var em = dmgParticleSystem.emission;
        em.enabled = false;
    }

    private void HandleAttacks()
    {

        if (canWalk == true)
        {
            /*            if (EquipmentUIManager.Instance.GetList().Count() == 0 || EquipmentUIManager.Instance.GetList().Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.WeaponSlot && el.Value != null).Count() == 0)
                            return;*/

            if (attackFist)
            {
                myAnimator.SetTrigger("attackFist");
            } else if (attackSword &&
                EquipmentUIManager.Instance.GetList().Count() != 0 &&
                EquipmentUIManager.Instance.GetList()
                    .Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.WeaponSlot && el.Value != null).Count() > 0 &&
                EquipmentUIManager.Instance.GetList()
                    .Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.WeaponSlot && el.Value != null).First().Value.Name.Equals("Pickaxe"))
            {
                myAnimator.SetTrigger("pickaxe");
            }
            else if (attackSword &&
                EquipmentUIManager.Instance.GetList().Count() != 0 &&
                EquipmentUIManager.Instance.GetList()
                    .Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.WeaponSlot && el.Value != null).Count() > 0 &&
                EquipmentUIManager.Instance.GetList()
                    .Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.WeaponSlot && el.Value != null).First().Value.EquipmentType == EquipmentTypeEnum.Weapon)
            {
                myAnimator.SetTrigger("attack");
            }
        }

    }

    private void HandleInput()
    {
        KeyCode keyToAttack = (KeyCode) System.Enum.Parse(typeof(KeyCode), PlayerPrefs.GetString("Attack"));

        if (Input.GetKeyDown(keyToAttack))
        {
            attackSword = true;
        }
        if (Input.GetKeyDown(KeyCode.LeftShift))
        {
            attackFist = true;
        }
        if (Input.GetKeyDown(KeyCode.X))
        {
            pickaxeInUse = true;
        }
    }

    private void ResetValues()
    {
        attackSword = false;
        attackFist = false;
        pickaxeInUse = false;
    }

    void Update()
    {

        if (lvlUp == true)
        {
            PlayerPrefs.SetInt("LvlUpPopUp", 1);
            exp = 0;
            lvlUp = false;
        }

        ManageHealth();
        ManageDefense();
        ManageIntelligence();
        ManageStrength();
        ManageSpeed();

        if (canWalk == true)
        {

            inputHorizontal = Input.GetAxisRaw("Horizontal");
            inputVertical = Input.GetAxisRaw("Vertical");

            // speed calculated in ManageSpeed function
            walkSpeed = PlayerPrefs.GetFloat("speed");

            myAnimator.SetFloat("moveX", inputHorizontal * walkSpeed);
            myAnimator.SetFloat("moveY", inputVertical * walkSpeed);

            if (inputHorizontal != 0)
            {
                myAnimator.SetFloat("speed", walkSpeed);
            }
            else if (inputVertical != 0)
            {
                myAnimator.SetFloat("speed", walkSpeed);
            }
            else
            {
                myAnimator.SetFloat("speed", 0);
            }

            if (inputHorizontal == 1 || inputHorizontal == -1 || inputVertical == 1 || inputVertical == -1)
            {
                myAnimator.SetFloat("lastMoveX", inputHorizontal);
                myAnimator.SetFloat("lastMoveY", inputVertical);
            }

            timerRegen += Time.deltaTime;
            if (timerRegen >= waitRegen)
            {
                startRegen = true;
            }

            currentHealth = PlayerPrefs.GetFloat("health");
            maxHealth = PlayerPrefs.GetFloat("maxHealth");
            if (startRegen == true)
            {
                timerTick += Time.deltaTime;
                if (timerTick >= waitTick)
                {
                    if (currentHealth < maxHealth)
                    {
                        currentHealth = currentHealth + 1;
                        if (currentHealth > maxHealth)
                        {
                            currentHealth = maxHealth;
                        }
                        PlayerPrefs.SetFloat("health", currentHealth);
                        timerTick = 0f;
                    }
                }
            }
            PlayerPrefs.SetFloat("health", currentHealth);
            PlayerPrefs.SetFloat("exp", exp);
            PlayerPrefs.SetInt("lvl", lvl);
            PlayerPrefs.SetFloat("maxExp", maxExp);
            PlayerPrefs.SetFloat("maxHealth", maxHealth);
        }

        HandleInput();
    }

    void FixedUpdate()
    {
        if (canWalk == true)
        {
            if (inputHorizontal != 0 || inputVertical != 0)
            {
                if (inputHorizontal != 0 && inputVertical != 0)
                {
                    inputHorizontal *= speedLimiter;
                    inputVertical *= speedLimiter;
                }
                rb.velocity = new Vector2(inputHorizontal * walkSpeed, inputVertical * walkSpeed);
            }
            else
            {
                rb.velocity = new Vector2(0f, 0f);
            }
        }

        HandleAttacks();
        ResetValues();
    }

    public void SaveCheckpoint()
    {
        currentHealth = PlayerPrefs.GetFloat("health");
        PlayerPrefs.SetFloat("health-S", currentHealth);
        PlayerPrefs.SetFloat("exp-S", exp);
        PlayerPrefs.SetInt("lvl-S", lvl);
    }

    public void ManageHealth()
    {
        //nie wiem czy to potrzebne ale zostawiam tak
        healthPoints = PlayerPrefs.GetInt(SkillsPointsManger.PLAYER_SKILS_HEALTH_POINTS);


        // nowe - analogicznie jak w ataku
        var healthCalculltor = new HealthCalcullator();

        var health = BaseHealth + healthCalculltor.CalculateWithoutItem();

        PlayerPrefs.SetFloat("maxHealth", health);

        //Debug.Log("Health: " + PlayerPrefs.GetFloat("maxHealth"));
    }

    public void AddHealthPoint()
    {
        healthPoints = PlayerPrefs.GetInt(SkillsPointsManger.PLAYER_SKILS_HEALTH_POINTS);
        healthPoints = healthPoints + 1;
        PlayerPrefs.SetInt(SkillsPointsManger.PLAYER_SKILS_HEALTH_POINTS, healthPoints);

        // Fetch change in scene manager responsible for this data
        SkillsPointsManger.Instance.UpdatePanelView();
    }

    public void ManageStrength()
    {
        if (EquipmentUIManager.Instance.GetList().Count() == 0 || EquipmentUIManager.Instance.GetList().Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.WeaponSlot && el.Value != null).Count() == 0)
        {
            var attackCalculator = new AttackCalcullator();

            attackValue = attackCalculator.CalculateWithoutItem();

            PlayerPrefs.SetFloat("attackValue", attackValue);
        }
        else if (EquipmentUIManager.Instance.GetList().Count() != 0 &&
            EquipmentUIManager.Instance.GetList().Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.WeaponSlot && el.Value != null).Count() > 0 &&
            EquipmentUIManager.Instance.GetList().Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.WeaponSlot && el.Value != null).First().Value.EquipmentType == EquipmentTypeEnum.Weapon)
        {
            var equippedItem = EquipmentUIManager.Instance.GetList().Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.WeaponSlot && el.Value != null).First().Value;

            var attackCalculator = new AttackCalcullator();

            attackValue = attackCalculator.Calculate(equippedItem.Value);
            
            PlayerPrefs.SetFloat("attackValue", attackValue);
        } else
        {
            throw new System.Exception("Attack Calculation Error");
        }

        //Debug.Log("Attack: " + PlayerPrefs.GetFloat("attackValue"));
    }

    public void AddStrengthPoint()
    {
        strengthPoints = PlayerPrefs.GetInt(SkillsPointsManger.PLAYER_SKILS_STRENGHT_POINTS);
        strengthPoints = strengthPoints + 1;
        PlayerPrefs.SetInt(SkillsPointsManger.PLAYER_SKILS_STRENGHT_POINTS, strengthPoints);

        // Fetch change in scene manager responsible for this data
        SkillsPointsManger.Instance.UpdatePanelView();
    }

    public void ManageDefense()
    {
        //nie wiem czy to potrzebne ale zostawiam tak
        defensePoints = PlayerPrefs.GetInt(SkillsPointsManger.PLAYER_SKILS_DEFENSE_POINTS);

        // nowe - analogicznie jak w ataku
        var defenseCalculator = new DefenseCalculattor();

        if (EquipmentUIManager.Instance.GetList().Count() == 0 ||
            EquipmentUIManager.Instance.GetList().Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.HelmetSlot && el.Value != null).Count() == 0 &&
            EquipmentUIManager.Instance.GetList().Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.ArmorSlot && el.Value != null).Count() == 0
        ){

            defenseValue = defenseCalculator.CalculateWithoutItem();

            PlayerPrefs.SetFloat("defenseValue", defenseValue);
        }
        else if (EquipmentUIManager.Instance.GetList().Count() != 0 &&
            
            (EquipmentUIManager.Instance.GetList()
                .Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.HelmetSlot && el.Value != null).Count() > 0 &&
            EquipmentUIManager.Instance.GetList()
                .Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.HelmetSlot && el.Value != null).First().Value.EquipmentType == EquipmentTypeEnum.Helmet) ||
                            
            (EquipmentUIManager.Instance.GetList()
                .Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.ArmorSlot && el.Value != null).Count() > 0 &&
            EquipmentUIManager.Instance.GetList()
                .Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.ArmorSlot && el.Value != null).First().Value.EquipmentType == EquipmentTypeEnum.Chest)
        ) {
            var helmetSlot = EquipmentUIManager.Instance.GetList().Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.HelmetSlot && el.Value != null);
            var helmet = (helmetSlot.Count() != 0) ? helmetSlot.First().Value.Value : 0;


            var chestplateSlot = EquipmentUIManager.Instance.GetList().Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.ArmorSlot && el.Value != null);
            var chestplate = (chestplateSlot.Count() != 0) ? chestplateSlot.First().Value.Value : 0;


            defenseValue = defenseCalculator.Calculate(helmet + chestplate);

            PlayerPrefs.SetFloat("defenseValue", defenseValue);
        }
        else
        {
            throw new System.Exception("Defense Calculation Error");
        }

        //Debug.Log("Defense: " + PlayerPrefs.GetFloat("defenseValue"));
    }

    public void AddDefensePoint()
    {
        defensePoints = PlayerPrefs.GetInt(SkillsPointsManger.PLAYER_SKILS_DEFENSE_POINTS);
        defensePoints = defensePoints + 1;
        PlayerPrefs.SetInt(SkillsPointsManger.PLAYER_SKILS_DEFENSE_POINTS, defensePoints);

        // Fetch change in scene manager responsible for this data
        SkillsPointsManger.Instance.UpdatePanelView();
    }

    public void ManageIntelligence()
    {
        intelligencePoints = PlayerPrefs.GetInt(SkillsPointsManger.PLAYER_SKILS_INTELIGENCE_POINTS);
    }

    public void AddIntelligencePoint()
    {
        intelligencePoints = PlayerPrefs.GetInt(SkillsPointsManger.PLAYER_SKILS_INTELIGENCE_POINTS);
        intelligencePoints = intelligencePoints + 1;
        PlayerPrefs.SetInt(SkillsPointsManger.PLAYER_SKILS_INTELIGENCE_POINTS, intelligencePoints);

        // Fetch change in scene manager responsible for this data
        SkillsPointsManger.Instance.UpdatePanelView();
    }

    public void LevelUpPopUp()
    {
        healthPoints = PlayerPrefs.GetInt(SkillsPointsManger.PLAYER_SKILS_HEALTH_POINTS);
    }

    public void ManageSpeed()
    {
        var speed = 0f;
        var speedCalculator = new SpeedCalcullator();

        if (EquipmentUIManager.Instance.GetList().Count() == 0 || EquipmentUIManager.Instance.GetList().Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.BootsSlot && el.Value != null).Count() == 0)
        {
            speed = BaseSpeed + speedCalculator.CalculateWithoutItem();

        }
        else if (EquipmentUIManager.Instance.GetList().Count() != 0 &&
            EquipmentUIManager.Instance.GetList().Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.BootsSlot && el.Value != null).Count() > 0 &&
            EquipmentUIManager.Instance.GetList().Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.BootsSlot && el.Value != null).First().Value.EquipmentType == EquipmentTypeEnum.Boots)
        {
            var boots = EquipmentUIManager.Instance.GetList().Where(el => el.Key == (int)EquipmentPanelSlotsTypeEnum.BootsSlot && el.Value != null).First().Value;

            speed = BaseSpeed + speedCalculator.Calculate(boots.Value);
        }


        PlayerPrefs.SetFloat("speed", speed);

        //Debug.Log("Speed: " + PlayerPrefs.GetFloat("speed"));
    }
    
    // nowe - analogicznie jak w ataku

}