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

public class Player : Character {

    //[SerializeField]
    //private bool UseMouse = false;

    [SerializeField]
    private AudioClip HitEnemySound;

    private EnemyAI[] Enemies;

    private bool IsMovingBackwards { get; set; }
    public bool IsAutoAiming { get; private set; }

    // Overrides the WeaponState defined in the Character class to use the one defined in the player manager instead.
    override protected WeaponStates WeaponState
    {
        get { return Managers.Player.WeaponState; }
        set { Managers.Player.WeaponState = value; }
    }


    protected override void Awake()
    {
        base.Awake();
        isPlayer = true;

        UpdateEnemies();
        Messenger<float>.AddListener(GameEvent.HIT_PLAYER, OnHitPlayer);
        Messenger.AddListener(GameEvent.ENEMY_COUNT_CHANGED, UpdateEnemies);
    }

    // Use this for initialization
    protected override void Start () {
        base.Start();
        // Initialise the player manager's health
        // Health = 10;
        Managers.Player.Health = HealthPercent;
	}

    private void OnDestroy()
    {
        Messenger<float>.RemoveListener(GameEvent.HIT_PLAYER, OnHitPlayer);
        Messenger.RemoveListener(GameEvent.ENEMY_COUNT_CHANGED, UpdateEnemies);
    }

    // Update is called once per frame
    void Update () {
        if (Managers.IsGameOver)
            return;

        string keyPressed = Input.inputString;

        // TO DO: Apply Weapon Change
        // Check that a key was pressed AND check that it was a numeric key
        // If yes, call ApplyWeaponChange passing the number pressed
        if (!string.IsNullOrEmpty(keyPressed) && char.IsDigit(keyPressed, 0))
        {
            ApplyWeaponChange(int.Parse(keyPressed));
        }
                
        ApplyGravity();

        if (!IsJumping)
        {
            IsAttacking = Input.GetKey(KeyCode.E); // && WeaponState != WeaponStates.Unarmed;
            // Debug.Log("Player attacking: " + IsAttacking);
            if (IsAttacking)
            {
                // Debug.Log("Player attacking: " + IsAttacking);
            }
            else
            {
                // Show Laser
                IsRunning = (Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift));
                ApplyMoveDirection();
                ApplyMoveSpeed();
                ApplyJumping(Input.GetButtonDown("Jump"));
            }
        } else
        {

        }


        // Finally update the movement
        if (!IsAttacking)
        {
            UpdateMovement();
        }

	}

    private void UpdateEnemies()
    {
        Enemies = GameObject.FindObjectsOfType<EnemyAI>();
        // Debug.Log("I have " + Enemies.Length + " enemies");
    }

    protected override Vector3 GetTargetDirection()
    {
        // Read input on horizontal and vertical axis
        float horInput = Input.GetAxis("Horizontal");
        float vertInput = Input.GetAxis("Vertical");

        
        IsMoving = (horInput != 0 || vertInput != 0);

        // Get the camera's current transform - use as focal point
        Transform cameraTransform = Camera.main.transform;

        // transform it from local space to world space in the forward direction
        Vector3 forward = cameraTransform.TransformDirection(Vector3.forward);

        // Limit movement to backwards and forwards and sideways
        // Keep y fixed at zero as we do not want to move up and down
        forward.y = 0f;

        // Get the direction if moving sideways (left -> right movement)
        // Get the sideways direction (assuming left -> right movement)
        // Forward Vector is (0, 0, 1), Right Vector is (1
        // http://answers.unity3d.com/questions/228203/getting-vector-which-is-pointing-to-the-rightleft.html
        // http://answers.unity3d.com/questions/951452/calculate-rightleft-vectors-for-a-relative-vector.html
        Vector3 right = new Vector3(forward.z, 0f, -forward.x);

        // Check if character is moving backwards (vertical input will be negativie)
        if (vertInput < 0) {
            IsMovingBackwards = true;
        } else
        {
            IsMovingBackwards = false;
        }

        // Apply the keyboard input in the direction of the keys pressed
        // Move forward in direction of forward direction
        // Move sideways in direction of sideways direction
        Vector3 targetDirection = (horInput * right) + (vertInput * forward);

        // return the direction
        return targetDirection;
    }

    private void OnHitPlayer(float damage)
    {
        Hurt(damage);
        // Debug.Log(Health);
        if (Health == 0)
        {
            Die(DeathTypes.a);
            
        }
        Managers.Player.Health = HealthPercent;    
    }

    override protected bool CheckHitTarget()
    {
        if (Enemies == null)
        {
            return false;
        }

        RaycastHit hit;
        Transform[] attackWeapons;
        float attackDistance = ShootRange;


        switch (WeaponState)
        {
            case WeaponStates.Unarmed:
                // Character is fighting with hands, attack distance needs to be smaller
                attackWeapons = hands;
                attackDistance = HandsAttackRange;
                break;
            default:
                // Get the current weapons character is kitted with from the outfitter script
                attackWeapons = weaponsOutfitter.GetCurrentWeapons();
                break;
        }

        foreach (Transform weapon in attackWeapons)
        {
            foreach (EnemyAI enemy in Enemies)
            {
                if (enemy == null) { continue; }
                Transform Target = enemy.gameObject.transform;
                Vector3 distanceToTarget = Target.position - weapon.position;
                float sqrDistance = distanceToTarget.sqrMagnitude;
                if (Physics.Raycast(weapon.position, distanceToTarget.normalized, out hit, attackDistance))
                {
                    if (hit.transform.CompareTag("Enemy"))
                    {
                        // Debug.Log("hit the " + hit.transform.name + " at " + sqrDistance);

                        if (HitEnemySound != null)
                        {
                            Managers.Audio.PlaySound(HitEnemySound);
                        }

                        Messenger<float>.Broadcast(GameEvent.HIT_ENEMY, Damage);
                        return true;
                    }
                }
            }
        }

        return false;
    }

}
