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

public class Player : MonoBehaviour
{
    [Header("General")]
    [HideInInspector] public int currentHealth;
    public int maxHealth;

    [SerializeField] private float moveSpeed;

    [Header("GFX")]
    [SerializeField] private Transform GFX;

    [Header("Weapon")]
    private bool canShoot = true;
    [SerializeField] private WeaponManager weaponManager;

    [SerializeField] private Transform weaponPos;

    private float attackTimer;

    [Header("Melee")]
    [SerializeField] private Transform meleeAttackPoint;
    [SerializeField] private GameObject meleeWeaponGFX;
    [SerializeField] private int meleeAttackRate;
    private float meleeAttackTimer;

    [SerializeField] private GameObject meleeCollPrefab;
    [SerializeField] private float meleeAttackCollSpeed;

    [SerializeField] private float meleeAttackRange;
    [SerializeField] private int meleeAttackDamage;
    [Space]
    [SerializeField] private LayerMask enemyLayers;

    [Header("Armor")]
    public int armorLevel;
    [SerializeField] private int[] armorHealth;
    [Space]
    [SerializeField] private SpriteRenderer armorSpriteRenderer;
    [SerializeField] private Sprite[] armorGFX;

    [Header("Items")]
    [SerializeField] private GameObject bottle;
    [SerializeField] private int currentHealthPotions;
    [SerializeField] private int maxHealthPotions;

    [Header("Animator")]
    [SerializeField] private Animator anim;

    [Header("Audio")]
    [SerializeField] private AudioSource audioSource;

    [SerializeField] private AudioClip[] shootSound;
    [SerializeField] private AudioClip reloadSound;

    [SerializeField] private AudioClip changeWeaponSound;
    [SerializeField] private AudioClip meleeSound;

    [SerializeField] private AudioClip consumePotionSound;
    [SerializeField] private AudioClip woundSound;

    [Header("Waypoint")]
    private bool canUseWaypoint = false;
    private WaypointDirection waypointDirection;

    [Header("Trading")]
    private GameObject tradeMan;
    private bool canTrade;
    private int money;

    [Header("Other")]
	[SerializeField] private GameObject bulletPrefab;
    [SerializeField] private GameObject deathEffect;
    [SerializeField] private GameObject shootEffect;

    [SerializeField] private GameObject stepEffect;
    [SerializeField] private Transform legsPos;

    private float stepTimer;
    private Vector3 mousePos;
    private Rigidbody2D rig;

    void Start()
    {
        rig = GetComponent<Rigidbody2D>();
        maxHealth = armorHealth[armorLevel];
        currentHealth = maxHealth;
        Game.game.ui.SetHealthSliderMaxValue(maxHealth);
        Game.game.ui.SetHealthPotionsUI();
        Game.game.ui.SetAmmoText();

        ChangeArmor(armorLevel);

        Camera cam = Camera.main;
    }

    public void SetActivePlayer(bool value)
    {
        gameObject.GetComponent<Player>().enabled = value;
    }

	void Update ()
	{
		attackTimer += Time.deltaTime;
        meleeAttackTimer += Time.deltaTime;
        stepTimer += Time.deltaTime;

        Inputs();
	}

    void Inputs()
    {
        mousePos = Camera.main.ScreenToWorldPoint(Input.mousePosition);
        mousePos = new Vector3(mousePos.x, mousePos.y, 0);

        // Стрельба
        if (Input.GetButton("Fire1"))
        {
            if (attackTimer >= weaponManager.currentWeapon.attackRate && canShoot == true)
            {
                attackTimer = 0.0f;
                Shoot();
            }
        }

        // Перезарядка
        if (Input.GetButtonDown("Reload"))
        {
            StartCoroutine(Reload());
        }

        // Рукопашный бой
        if (Input.GetButtonDown("MeleeAttack"))
        {
            if (meleeAttackTimer >= meleeAttackRate)
            {
                meleeAttackTimer = 0.0f;
                StartCoroutine(MeleeAtack());
            }
        }

        // Использование вэйпойнта
        if (canUseWaypoint == true)
        {
            if (Input.GetButtonDown("Use"))
            {
                StartCoroutine(Game.game.map.GoToNextLocation(waypointDirection));
                gameObject.GetComponent<Player>().enabled = false;
            }
        }

        // Торговля
        if (canTrade == true)
        {
            if (Input.GetButtonDown("Use"))
            {
                SetActivePlayer(false);

                tradeMan.GetComponent<Trade>().SetActiveTradeMenu(true);
                Game.game.ui.ChangeCursor(0);
            }
        }

        // Употребление зелья здоровья
        if (Input.GetButtonDown("Consume"))
        {
            ConsumeHealthPotion();
        }

        // Смена оружия
        if (Input.GetButtonDown("Pistol"))
        {
            ChangeToNewWeapon(0);
        }
        else if (Input.GetButtonDown("MachineGun"))
        {
            ChangeToNewWeapon(1);
        }
        else if (Input.GetButtonDown("ShotGun"))
        {
            ChangeToNewWeapon(2);
        }
        else if (Input.GetButtonDown("Rifle"))
        {
            ChangeToNewWeapon(3);
        }

        //Чит-коды
        if (Input.GetKeyDown(KeyCode.Comma))
        {
            money = 999;
            currentHealth = 999;

            Game.game.ui.SetMoneyText();
            Game.game.ui.SetHealthSliderValue(currentHealth);
        }
    }

    void FixedUpdate()
    {
        // Передвижение
        Move(Input.GetAxis("Horizontal"), Input.GetAxis("Vertical"));

        // Поворот за курсором
        PlayerFlip();
        weaponPos.rotation = Quaternion.Lerp(weaponPos.rotation, WeaponRotation(), weaponManager.currentWeapon.rotationSpeed * Time.deltaTime);
    }

    // Передвижение игрока (установка X и Y координат)
    void Move(float x, float y)
    {
        rig.velocity = new Vector2(x, y) * moveSpeed;

        anim.SetFloat("moveSpeed", Mathf.Abs(rig.velocity.magnitude));

        MoveEffect(0.25f);
    }

    // Эффект пыли при ходьбе
    void MoveEffect(float stepRate)
    {
        if (anim.GetFloat("moveSpeed") > 0f)
        {
            if (stepTimer >= stepRate)
            {
                stepTimer = 0.0f;
                GameObject walkFX = Instantiate(stepEffect, legsPos.position, legsPos.rotation);
                Destroy(walkFX, 3f);
            }
        }
    }

    // Ближний бой
    IEnumerator MeleeAtack()
    {
        canShoot = false;

        anim.SetTrigger("meleeAttack");
        audioSource.PlayOneShot(meleeSound);

        meleeWeaponGFX.SetActive(true);
        weaponManager.SetActiveWeaponGFX(false);

        Collider2D[] hitEnemies = Physics2D.OverlapCircleAll(meleeAttackPoint.position, meleeAttackRange, enemyLayers);

        foreach (Collider2D enemy in hitEnemies)
        {
            enemy.GetComponent<Enemy>().TakeDamage(meleeAttackDamage);
        }

        GameObject proj = Instantiate(meleeCollPrefab, meleeAttackPoint.position, meleeAttackPoint.rotation);
        Rigidbody2D projRig = proj.GetComponent<Rigidbody2D>();

        Vector3 mousePos = GetMousePosition();

        projRig.velocity = (mousePos - transform.position).normalized * meleeAttackCollSpeed;

        Destroy(proj, 0.5f);

        yield return new WaitForSeconds(meleeAttackRate);

        meleeWeaponGFX.SetActive(false);
        weaponManager.SetActiveWeaponGFX(true);

        canShoot = true;
    }

    void OnDrawGizmosSelected()
    {
        if (meleeAttackPoint == null)
            return;

        Gizmos.DrawWireSphere(meleeAttackPoint.position, meleeAttackRange);
    }

	// Стрельба (Спавнит проджектайл и двигает его вправо)
	void Shoot ()
	{
        if (weaponManager.WeaponShoot() == true)
        {
            Game.game.ui.SetAmmoText();
            anim.SetTrigger("shoot");

            audioSource.PlayOneShot(shootSound[weaponManager.currentWeapon.weaponType]);
        }
	}

    IEnumerator Reload()
    {
        if (weaponManager.WeaponReload() == true)
        {
            canShoot = false;

            anim.SetTrigger("reload");
            audioSource.PlayOneShot(reloadSound);

            float t = weaponManager.GetWeaponReloadTime();
            yield return new WaitForSeconds(t);

            canShoot = true;

            Game.game.ui.SetAmmoText();
        }
    }

    // Смена на другое оружие (механика, анимация, звуки и т.п.)
    public void ChangeToNewWeapon(int value)
    {
        if (weaponManager.ChangeWeapon(value) == true)
        {
            anim.SetTrigger("change weapon");
            audioSource.PlayOneShot(changeWeaponSound);

            weaponManager.SetUpWeapon();
            Game.game.ui.SetUpWeaponUI();
            Game.game.ui.SetAmmoText();
        }
    }

    // Смена брони
    public void ChangeArmor(int value)
    {
        armorSpriteRenderer.sprite = armorGFX[value];
    }

    // Приобретение новой брони
    public void UpgradeArmor()
    {
        armorLevel += 1;
        maxHealth = armorHealth[armorLevel];
        currentHealth = maxHealth;

        Game.game.ui.SetHealthSliderMaxValue(maxHealth);
        Game.game.ui.SetHealthSliderValue(currentHealth);
    }

    public Vector3 GetMousePosition()
    {
        return mousePos;
    }

    //  Получаем угол между позицией игрока и курсора мыши
    float GetAngle()
    {
        Vector2 lookDir = mousePos - transform.position;
        float angle = Mathf.Atan2(lookDir.y, lookDir.x) * Mathf.Rad2Deg;

        return angle;
    }

    // Разворачивание игрока и его правильное отображение
    void PlayerFlip()
    {
        Vector3 rotationVector = transform.rotation.eulerAngles;
        float angle = GetAngle();

        if (angle > 90f || angle < -90f)
        {
            rotationVector.y = 180f;
            GFX.transform.rotation = Quaternion.Euler(rotationVector);
        }
        else if (angle < 90f || angle > -90f)
        {
            rotationVector.y = 0f;
            GFX.transform.rotation = Quaternion.Euler(rotationVector);
        }
    }

    // Поворот оружия и его правильное отображение
    Quaternion WeaponRotation()
    {
        float angle = GetAngle();

        if (angle > 90f || angle < -90f)
        {
            weaponPos.localScale = new Vector3(1f, -1f, 0f);
        }
        else if (angle < 90f || angle > -90f)
        {
            weaponPos.localScale = new Vector3(1f, 1f, 0f);
        }

        return Quaternion.AngleAxis(angle, Vector3.forward);
    }

	// Принятие урона
	public void TakeDamage (int dmg)
	{
		if(currentHealth - dmg <= 0)
		{
			Die();
		}
		else
		{
            audioSource.PlayOneShot(woundSound);

            currentHealth -= dmg;
            Game.game.ui.SetHealthSliderValue(currentHealth);
		}
	}

    // Принятие зелья здоровья
    void ConsumeHealthPotion()
    {
        if (currentHealthPotions > 0)
        {
            StartCoroutine(DrinkPotion());

            anim.SetTrigger("consumePotion");
            audioSource.PlayOneShot(consumePotionSound);

            currentHealth = maxHealth;
            currentHealthPotions -= 1;

            Game.game.ui.SetHealthSliderValue(currentHealth);
            Game.game.ui.SetHealthPotionsUI();
        }
    }

    IEnumerator DrinkPotion()
    {
        bottle.SetActive(true);

        yield return new WaitForSeconds(2f);

        bottle.SetActive(false);
    }

    public bool CanAddHealthPotion()
    {
        if (currentHealthPotions < maxHealthPotions)
        {
            return true;
        }

        return false;
    }

    public int GetCurrentHealthPotions()
    {
        return currentHealthPotions;
    }

    public int GetMaxHealthPotions()
    {
        return maxHealthPotions;
    }

    public void AddHealthPotion()
    {
        currentHealthPotions += 1;
        Game.game.ui.SetHealthPotionsUI();
    }

    public int GetMoneyAmount()
    {
        return money;
    }

    // Добавление денег
    public void AddMoney(int value)
    {
        money += value;
    }

    // Отнимание денег
    public bool SubtractMoney(int value)
    {
        if (money >= value)
        {
            money -= value;
            return true;
        }

        return false;
    }

    // Остановка/заморозка движения
    public void FreezeMovement(bool value)
    {
        rig.simulated = !value;
    }

    void OnTriggerEnter2D(Collider2D coll)
    {
        // Подбор монеток
        if(coll.tag == "Coin")
        {
            money += 1;
            Destroy(coll);
        }
    }

    void OnTriggerStay2D(Collider2D coll)
    {
        if (coll.tag == "Waypoint")
        {
            if (coll.GetComponent<Waypoint>().isOpen == true)
            {
                canUseWaypoint = true;
                waypointDirection = coll.GetComponent<Waypoint>().waypointDirection;
                Game.game.ui.SetTextHelp(true);
            }
        }

        if (coll.tag == "Trader")
        {
            canTrade = true;
            tradeMan = coll.gameObject;
            Game.game.ui.SetTextHelp(true);
        }
    }

    void OnTriggerExit2D(Collider2D coll)
    {
        if (coll.tag == "Waypoint")
        {
            canUseWaypoint = false;
            Game.game.ui.SetTextHelp(false);
        }
        if (coll.tag == "Trader")
        {
            canTrade = false;
            Game.game.ui.SetTextHelp(false);
        }
    }

	// Погибель
	void Die ()
	{
        FreezeMovement(true);

		currentHealth = 0;
        Game.game.ui.SetHealthSliderValue(currentHealth);

		GameObject pe = Instantiate(deathEffect, transform.position, Quaternion.identity);
		Destroy(pe, 2f);

        anim.SetBool("death", true);

        Game.game.ui.StartCoroutine(Game.game.ui.DeathScreen());

        GetComponent<Player>().enabled = false;
	}

    public void SetLoadedValues(PlayerData data)
    {
        money = data.money;
        
        armorLevel = data.armorLevel;
        currentHealth = data.currentHealth;
        maxHealth = data.maxHealth;
        currentHealthPotions = data.currentHealthPotion;

        print("Set loaded value succesfull!");
    }

    public PlayerData GetSavedValues(PlayerData data)
    {
        data.money = money;

        data.armorLevel = armorLevel;
        data.currentHealth = currentHealth;
        data.maxHealth = maxHealth;
        data.currentHealthPotion = currentHealthPotions;

        print("Saved value money: " + money);

        return data;
    }
}
