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

public class GojiController : MonoBehaviour
{
    enum GojiState
    {
        NONE, Hidden, Rising, Idle, Hit, Hiding, ChargingUp, DEAD
    }

    private GojiState _state;

    private GojiState State
    {
        set
        {
            switch (value)
            {
                case GojiState.Hidden:
                    transform.position = HIDDEN_POSITION;
                    timeElapsedSinceLastAppearance = 0f;
                    HP = MAX_HP;
                    break;
                case GojiState.Rising:
                    break;
                case GojiState.Idle:
                    timeElapsedSinceIdle = 0f;
                    break;
                case GojiState.ChargingUp:
                    timeElapsedSinceChargingUp = 0f;
                    break;
                default:
                    break;
            }

            _state = value;
        }

        get
        {
            return _state;
        }
    }

    public float RISE_SPEED;
    public float SPAWN_PERIOD;
    public float DELAY_TO_START_CHARGING_UP;
    public float CHARGE_UP_TIME;
    public Vector2 fireBallSpawnOffset;
    public float fireBallLaunchMagnitude;
    public float speed;
    public float threshold;
    public int MAX_HP;
    private int HP;

    public SpriteRenderer spriteRenderer;
    public GameObject fireBall;
    private GameObject currentFireBall;

    private float timeElapsedSinceLastAppearance;
    private float timeElapsedSinceHit;
    private float timeElapsedSinceIdle;
    private float timeElapsedSinceChargingUp;

    private Vector2 HIDDEN_POSITION = new Vector2(6.36f, -11.1f);
    private Vector2 RISE_POSITION = new Vector2(6.36f, -0.54f);

    // Use this for initialization
    void Start()
    {
        State = GojiState.Hidden;
    }

    // Update is called once per frame
    void FixedUpdate()
    {
        switch (State)
        {
            case GojiState.Hidden:
                timeElapsedSinceLastAppearance += Time.fixedDeltaTime;

                if (timeElapsedSinceLastAppearance >= SPAWN_PERIOD)
                {
                    Rise();
                }

                break;
            case GojiState.Rising:
                break;
            case GojiState.Idle:

                timeElapsedSinceIdle += Time.fixedDeltaTime;

                if (timeElapsedSinceIdle >= DELAY_TO_START_CHARGING_UP)
                {
                    ChargeUpHyperBeam();
                }

                break;

            case GojiState.ChargingUp:

                timeElapsedSinceChargingUp += Time.fixedDeltaTime;

                if (timeElapsedSinceChargingUp >= CHARGE_UP_TIME)
                {
                    FireHyperBeam();
                }

                break;

            case GojiState.Hit:
                break;
            case GojiState.Hiding:
                break;
            default:
                break;
        }

        if (State == GojiState.ChargingUp || State == GojiState.Idle)
        {
            if (Mathf.Abs(transform.position.x - PlayerController.instance.transform.position.x) > threshold)
            {
                transform.Translate(new Vector2(speed * Time.fixedDeltaTime * Mathf.Sign(-transform.position.x + PlayerController.instance.transform.position.x), 0f));
            }
        }

        var cameraLeftSideAbscissa = Camera.main.transform.position.x - Camera.main.orthographicSize * Camera.main.aspect - 2f;

        if (transform.position.x < cameraLeftSideAbscissa)
        {
            State = GojiState.Hidden;
        }
    }

    private void ChargeUpHyperBeam()
    {
        State = GojiState.ChargingUp;

        currentFireBall = Instantiate(fireBall, transform);
        var position = transform.position;
        position.x += fireBallSpawnOffset.x;
        position.y += fireBallSpawnOffset.y;
        currentFireBall.transform.position = position;
    }

    private void FireHyperBeam()
    {
        State = GojiState.Idle;

        currentFireBall.GetComponent<FireBallController>().FireAt(PlayerController.instance.transform.position, fireBallLaunchMagnitude);
    }

    //    void OnCollisionEnter2D(Collision2D collision)
    //    {
    //
    //    }

    void OnTriggerEnter2D(Collider2D collider)
    {
        if (collider.gameObject.CompareTag("CannonBall"))
        {
            Debug.Log("GOJI CANNONBALL HIT");
            TintHit();
            HP--;

            if (HP == 0)
            {
                Hide();
            }
        }
    }

    private void Hide()
    {
        StartCoroutine(Hide_Coroutine());
    }

    private IEnumerator Hide_Coroutine()
    {
        State = GojiState.Hiding;

        var hiddenPosition = transform.position;
        hiddenPosition.y = HIDDEN_POSITION.y;

        while (transform.position.y > HIDDEN_POSITION.y + 0.5f)
        {
            transform.position = Vector3.Lerp(transform.position, hiddenPosition, RISE_SPEED * Time.fixedDeltaTime);
            yield return new WaitForFixedUpdate();
        }

        State = GojiState.Hidden;
    }

    private void Rise()
    {
        StartCoroutine(Rise_Coroutine());
    }

    private IEnumerator Rise_Coroutine()
    {
        State = GojiState.Rising;
        AudioManager.Instance.PlayGojiAppear();

        while (transform.position.y < RISE_POSITION.y - 0.5f)
        {
            transform.position = Vector2.Lerp(transform.position, RISE_POSITION, RISE_SPEED * Time.fixedDeltaTime);
            yield return new WaitForFixedUpdate();
        }

        State = GojiState.Idle;
    }

    private void TintHit()
    {
        StopCoroutine("TintHit_Coroutine");
        StartCoroutine("TintHit_Coroutine");
    }

    private IEnumerator TintHit_Coroutine()
    {
        spriteRenderer.color = Color.red;

        var duration = 0.3f;
        var elapsedTime = 0f;

        while (elapsedTime <= duration)
        {
            elapsedTime += Time.deltaTime;
            var interpolant = elapsedTime / duration;

            spriteRenderer.color = Color.Lerp(Color.red, Color.white, interpolant);
            yield return new WaitForFixedUpdate();
        }

        spriteRenderer.color = Color.white;
    }
}
