using System;
using System.Collections;

using UnityEngine;

public class MovementController : MonoBehaviour
{
    public float MaxSpeed = 5f;

    public float MoveForce = 75f;
    public float JumpForce = 1200f;

    public bool AllowDoubleJump = false;
    public float DoubleJumpThreshold = 0.25f;

    public Transform[] GroundCheck;
    public LayerMask GroundMask;
    public float GroundRadius;

    public string Horizontal1 = "P1_Horizontal";
    public string Horizontal2 = "P2_Horizontal";

    public string Vertical1 = "P1_Vertical";
    public string Vertical2 = "P2_Vertical";

    public string Jump1 = "P1_Jump";
    public string Jump2 = "P2_Jump";

    public string Fire1 = "P1_Fire";
    public string Fire2 = "P2_Fire";

    public string Attack1 = "P1_Attack";
    public string Attack2 = "P2_Attack";

    public string MegaFire1 = "P1_MegaFire";
    public string MegaFire2 = "P2_MegaFire";

    public string MegaFire1Debug = "P1_MegaFireDebug";
    public string MegaFire2Debug = "P2_MegaFireDebug";

    public float HorizontalThreshold = 0.2f;
    public float VerticalThreshold = 0.2f;

    public float FireDelay = 0.7f;

    private bool _bFacingRight = true;
    private bool _bGrounded = false;

    private bool _bDoubleJump = false;

    private bool _bFire = false;

    private float _FireTimer = 0f;

    private Weapon _Weapon = null;
    private MegaShoot _MegaShoot = null;

    public bool bGrounded
    {
        get
        {
            return _bGrounded;
        }
    }

    public bool bFire
    {
        get
        {
            return _bFire;
        }
    }

    void Start()
    {
        if (Vector3.Dot(transform.right, Vector3.right) < 0f)
        {
            _bFacingRight = false;
        }

        _Weapon = (Weapon)GetComponent(typeof(Weapon));
        _MegaShoot = (MegaShoot)GetComponent(typeof(MegaShoot));

        if (_Weapon == null)
        {
            Debug.LogError("[" + gameObject.name + "] Weapon not found.");
        }

        if (_MegaShoot == null)
        {
            Debug.LogError("[" + gameObject.name + "] MegaShoot not found.");
        }
    }

    void FixedUpdate()
    {
        HandleHorizontalAxis();
    }

    void Update()
    {
        HandleJump();

        HandleFire();

        HandleMegaFire();

        HandleMegaFireDebug();

        HandleAttack();
    }

    private void Flip()
    {
        _bFacingRight = !_bFacingRight;

        transform.Rotate(Vector3.up, 180f);
    }

    private void HandleHorizontalAxis()
    {
        float move1 = Input.GetAxis(Horizontal1);
        float move2 = Input.GetAxis(Horizontal2);

        if ((Mathf.Abs(move1) > Mathf.Epsilon) && (Mathf.Abs(move2) > Mathf.Epsilon))
        {
            if (Mathf.Abs(move1 - move2) < HorizontalThreshold)
            {
                // Input from P1 and P2 matches. Move character.

                float move = (move1 + move2) * .5f;

                if (Mathf.Abs(move) > Mathf.Epsilon)
                {
                    if (move * rigidbody2D.velocity.x < MaxSpeed)
                    {
                        rigidbody2D.AddForce(move * MoveForce * Vector2.right);
                    }

                    if (Mathf.Abs(rigidbody2D.velocity.x) > MaxSpeed)
                    {
                        rigidbody2D.velocity = new Vector2(Mathf.Sign(rigidbody2D.velocity.x) * MaxSpeed, rigidbody2D.velocity.y);
                    }

                    if (move > Mathf.Epsilon)
                    {
                        if (!_bFacingRight)
                        {
                            Flip();
                        }
                    }
                    else
                    {
                        if (move < -Mathf.Epsilon)
                        {
                            if (_bFacingRight)
                            {
                                Flip();
                            }
                        }
                    }

                    Debug.Log("[" + gameObject.name + "] MOVING");
                }
            }
        }
    }

    private void HandleJump()
    {
        _bGrounded = false;

        foreach (Transform t in GroundCheck)
        {
            _bGrounded = _bGrounded || Physics2D.OverlapCircle(t.position, GroundRadius, GroundMask);
        }

        if (_bGrounded)
        {
            _bDoubleJump = false;
        }

        bool bJump = false;

        if (Input.GetButtonDown(Jump1))
        {
            if (Input.GetButton(Jump2))
            {
                bJump = true;
            }
        }
        else
        {
            if (Input.GetButtonDown(Jump2))
            {
                if (Input.GetButton(Jump1))
                {
                    bJump = true;
                }
            }
        }

        if (bJump)
        {
            // Input synchronized, jump.

            if ((_bGrounded || (!_bDoubleJump && ( rigidbody2D.velocity.y < DoubleJumpThreshold && AllowDoubleJump) )))
            {
                rigidbody2D.AddForce(new Vector2(0f, JumpForce));

                if (!_bDoubleJump && !_bGrounded)
                {
                    _bDoubleJump = true;
                }

                Debug.Log("[" + gameObject.name + "] JUMP");
            }
        }
    }

    private void HandleFire()
    {
        if (_Weapon != null)
        {
            _FireTimer += Time.deltaTime;

            _bFire = false;

            if (_FireTimer > FireDelay)
            {
                if (Input.GetButtonDown(Fire1))
                {
                    if (Input.GetButton(Fire2))
                    {
                        _bFire = true;
                    }
                }
                else
                {
                    if (Input.GetButtonDown(Fire2))
                    {
                        if (Input.GetButton(Fire1))
                        {
                            _bFire = true;
                        }
                    }
                }

                if (_bFire)
                {
                    _FireTimer = 0f;

                    _Weapon.Shoot(); // BOOM, baby!
                    
                    Debug.Log("[" + gameObject.name + "] FIRE");
                }
            }
        }
        else
        {
            _FireTimer = 0f;
            _bFire = false;
        }
    }

    private void HandleMegaFire()
    {
        if (_MegaShoot != null)
        {
            bool bMegaFire = false;

            if (Input.GetButtonDown(MegaFire1))
            {
                if (Input.GetButton(MegaFire2))
                {
                    bMegaFire = true;
                }
            }
            else
            {
                if (Input.GetButtonDown(MegaFire2))
                {
                    if (Input.GetButton(MegaFire1))
                    {
                        bMegaFire = true;
                    }
                }
            }

            if (bMegaFire)
            {
                Debug.Log("[" + gameObject.name + "] MEGA-FIRE");

                _MegaShoot.Shoot(); // BOOM, baby!
            }
        }
    }

    private void HandleMegaFireDebug()
    {
        if (_MegaShoot != null)
        {
            bool bMegaFire = false;

            if (Input.GetButtonDown(MegaFire1Debug))
            {
                if (Input.GetButton(MegaFire2Debug))
                {
                    bMegaFire = true;
                }
            }
            else
            {
                if (Input.GetButtonDown(MegaFire2Debug))
                {
                    if (Input.GetButton(MegaFire1Debug))
                    {
                        bMegaFire = true;
                    }
                }
            }

            if (bMegaFire)
            {
                Debug.Log("[" + gameObject.name + "] MEGA-FIRE");

                _MegaShoot.EnableMegaFire();
                _MegaShoot.Shoot(); // BOOM, baby!
            }
        }
    }

    private void HandleAttack()
    {
        bool bAttack = false;

        if (Input.GetButtonDown(Attack1))
        {
            if (Input.GetButton(Attack2))
            {
                bAttack = true;
            }
        }
        else
        {
            if (Input.GetButtonDown(Attack2))
            {
                if (Input.GetButton(Attack1))
                {
                    bAttack = true;
                }
            }
        }

        if (bAttack)
        {
            // TODO: Attack.

            Debug.Log("[" + gameObject.name + "] ATTACK");
        }
    }
}
