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

public enum PowerLevelLabel
{
    Low,
    Mid,
    High
}

public class Player : MonoBehaviour
{
    [SerializeField]
    private float powerLevel;

    private Color _powerLevelLow = Color.red;
    private Color _powerLevelMid = new Color(255, 165, 0);
    private Color _powerLevelHigh = Color.green;

    private GameObject[] _powerUp = new GameObject[3];
    private GameObject[] _powerDown = new GameObject[3];

    public float PowerLevel
    {
        get
        {
            return powerLevel;
        }
        set
        {
            float offset = value - powerLevel;
            powerLevel = value;
            powerLevel = Mathf.Clamp(powerLevel, 0, powerLevelMax);
            UpdatePowerBar();
            UpdatePowerIndicator(offset);
        }
    }
    public float PowerFactor
    {
        get
        {
            return powerLevel / powerLevelMax;
        }
    }

    public PowerLevelLabel PowerLevelName
    {
        get
        {
            if (PowerFactor >= 0 && PowerFactor < 1.0f / 3.0f)
            {
                return PowerLevelLabel.Low;
            }
            if (PowerFactor >= 1.0f / 3.0f && PowerFactor < 2.0f / 3.0f)
            {
                return PowerLevelLabel.Mid;
            }
            if (PowerFactor >= 2.0f / 3.0f && PowerFactor <= 1.0f)
            {
                return PowerLevelLabel.High;
            }
            return PowerLevelLabel.Low;
        }
    }

    private Color _powerLevelColor
    {
        get
        {
            switch (PowerLevelName)
            {
                case PowerLevelLabel.Low:
                    {
                        return _powerLevelLow;
                    };
                case PowerLevelLabel.Mid:
                    {
                        return _powerLevelMid;
                    };
                case PowerLevelLabel.High:
                    {
                        return _powerLevelHigh;
                    };
            }
            return Color.white;
        }
    }

    private void UpdatePowerBar()
    {
        gauge.Find("PowerBar").transform.localScale = new Vector3(1, PowerFactor, 1);
        gauge.GetComponentInChildren<Renderer>().material.color = _powerLevelColor;
    }

    float goodIndicatorTimeOut = 0;
    float badIndicatorTimeOut = 0;

    private void UpdatePowerIndicator(float offset)
    {
        if (offset < 0)
        {
            if (Mathf.Abs(offset) > 0)
                _powerDown[2].SetActive(true);
            if (Mathf.Abs(offset) >= bulletDegenRate)
                _powerDown[1].SetActive(true);
            if (Mathf.Abs(offset) >= 0.95)
                _powerDown[0].SetActive(true);
            badIndicatorTimeOut = 1.5f;
        }
        else
        {
            if (Mathf.Abs(offset) > 0)
                _powerUp[2].SetActive(true);
            if (Mathf.Abs(offset) > 0.45)
                _powerUp[1].SetActive(true);
            if (Mathf.Abs(offset) > 0.95)
                _powerUp[0].SetActive(true);
            goodIndicatorTimeOut = 1.5f;
        }
    }

    private void UpdatePowerIndicatorTimeout(ref float timeOut, GameObject[] powerIndicators)
    {
        if (timeOut > 0)
        {
            timeOut -= Time.deltaTime;
        }
        if (timeOut < 0)
        {
            for (int i = 0; i < 3; i++)
            {
                powerIndicators[i].SetActive(false);
            }
            timeOut = 0;
        }
    }
    private float walkingDegenTimer = 1.5f;
    private void UpdateWalkingDegen(float speed)
    {
        if (speed > 0.1)
        {
            if (walkingDegenTimer == 0)
            {
                PowerLevel -= movementDegenRate;
                walkingDegenTimer = 1.5f;
            }
            if (walkingDegenTimer > 0)
            {
                walkingDegenTimer -= Time.deltaTime;
            }
            if (walkingDegenTimer < 0)
            {
                walkingDegenTimer = 0f;
            }
        }
        if (speed <= 0.1)
        {
            walkingDegenTimer = 0;
        }
        //Debug.Log(speed + ", " + walkingDegenTimer);
    }

    public float movementDegenRate = 0.1f;
    public float bulletDegenRate = 0.2f;

    public float startSpeed = 5f;
    public float lookSmoothingSeconds = 0.05f;
    public float cameraSmoothingSeconds = 1;
    public float bulletUpBias = 0.1f;
    public float bulletForce = 10f;
    public float powerLevelMax = 8.0f;
    public Transform gunTransform;
    public Rigidbody bulletPrefab;
    public Light muzzleLight;
    public Transform gauge;

    private Vector3 inputDirection;
    private float speed;
    private Vector3 lookDirection;
    private float deadZone = 0.1f;
    private Vector3 lookVelocity;
    private Vector3 cameraOffset;
    private Vector3 cameraVelocity;
    private bool shooting = false;
    private float lightIntensity;
    private bool useMouseLook;

    // Use this for initialization
    void Start()
    {
        speed = startSpeed;
        cameraOffset = Camera.main.transform.position - transform.position;
        lightIntensity = muzzleLight.intensity;
        var joystickNames = Input.GetJoystickNames();
        useMouseLook = joystickNames.Length == 0 || string.IsNullOrEmpty(joystickNames[0]);
        if (useMouseLook)
        {
            lookSmoothingSeconds = 0;
        }

        _powerUp[0] = gauge.Find("PowerUp1").gameObject;
        _powerUp[1] = gauge.Find("PowerUp2").gameObject;
        _powerUp[2] = gauge.Find("PowerUp3").gameObject;
        _powerDown[0] = gauge.Find("PowerDown1").gameObject;
        _powerDown[1] = gauge.Find("PowerDown2").gameObject;
        _powerDown[2] = gauge.Find("PowerDown3").gameObject;

        for (int i = 0; i < 3; i++)
        {
            _powerUp[i].SetActive(false);
            _powerDown[i].SetActive(false);
        }
    }



    // Update is called once per frame
    void Update()
    {
        // TODO lerp movement direction
        GetInput();

        if (lookDirection.magnitude > deadZone)
            transform.forward = Vector3.SmoothDamp(transform.forward, lookDirection, ref lookVelocity, lookSmoothingSeconds);
        transform.position += inputDirection * speed * Time.deltaTime;

        UpdatePowerBar();
        UpdatePowerIndicatorTimeout(ref goodIndicatorTimeOut, _powerUp);
        UpdatePowerIndicatorTimeout(ref badIndicatorTimeOut, _powerDown);
        UpdateWalkingDegen(inputDirection.magnitude);

        Camera.main.transform.position = Vector3.SmoothDamp(Camera.main.transform.localPosition, TargetCameraPosition(), ref cameraVelocity, cameraSmoothingSeconds);

        if (shooting)
        {
            if (Time.frameCount % 2 == 0)
            {
                muzzleLight.intensity = 0;
            }
            else
            {
                muzzleLight.intensity = Random.Range(.5f, 2f) * lightIntensity;
            }
            Shoot();
        }
        else
        {
            muzzleLight.intensity = 0;
        }
    }


    int bulletCounter = 5;
    private void Shoot()
    {
        var rb = Instantiate<Rigidbody>(bulletPrefab);
        rb.transform.position = gunTransform.position;
        rb.transform.forward = gunTransform.forward;
        rb.AddForce(bulletForce * (transform.forward + Vector3.up * bulletUpBias), ForceMode.VelocityChange);
        Destroy(rb.gameObject, 2f);
        if (bulletCounter == 5)
        {
            PowerLevel -= bulletDegenRate;
        }
        if (bulletCounter >= 0)
        {
            bulletCounter--;
        }
        if (bulletCounter < 0)
        {
            bulletCounter = 5;
        }
    }

    private Vector3 TargetCameraPosition()
    {
        return transform.position + cameraOffset;
    }

    void GetInput()
    {
        shooting = Input.GetButton("Fire1");
        var padLook = new Vector3(
            Input.GetAxis("LookX"),
            0,
            -Input.GetAxis("LookY")
        );
        if (useMouseLook)
        {
            var mouseLook = Input.mousePosition - Camera.main.WorldToScreenPoint(transform.position);
            mouseLook.Normalize();
            lookDirection = new Vector3(mouseLook.x, 0, mouseLook.y);
        }
        else if (padLook.magnitude > 0.2f)
        {
            lookDirection = padLook.normalized;
        }
        inputDirection = new Vector3(
            Input.GetAxis("Horizontal"),
            0,
            Input.GetAxis("Vertical")
        ).normalized;
    }
}
