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

namespace ToadieTechnika.GGJ2018Game
{
    enum PhoneParts
    { 
        Head,
        Wifi,
        Body,
        Tail
    }

    public interface IPhoneUnit
    {
        void ControllableFunctions();
    }

    public class PhoneUnitScript : PoolableObject, IPhoneUnit
    {
        int m_UnitID;

        [Header("Parts")]
        [SerializeField]
        Transform m_SpritePartParentTransform;

        [SerializeField]
        SpriteRenderer[] m_SpriteRenderers;

        [Header("Components")]
        [SerializeField]
        ParticleSystem m_ParticleSystem;

        [SerializeField]
        Rigidbody2D m_Rigidbody2D;

        [SerializeField]
        BoxCollider2D m_BoxCollider2D;

        [Header("Values")]
        [SerializeField]
        float m_MoveSpeed = 5f;

        //Jump Values
        [Space]
        [SerializeField]
        float m_JumpForce = 15f;

        [SerializeField]
        float m_MaxJumpForce = 20f;

        [SerializeField]
        float m_additionalJumpForce = 0.68f;


        [Space]
        [SerializeField]
        Vector3 m_SineWaveManipulation;
        float m_SineTime;

        Vector2 m_NormalScale;
        bool
            m_onGround,
            m_onCeiling;

        #region Properties
        public int UnitID
        {
            get { return m_UnitID; }
            set { m_UnitID = value; }
        }

        public bool SetSelected
        {
            get { return m_Rigidbody2D.constraints == RigidbodyConstraints2D.FreezeRotation; }
            set
            {
                m_Rigidbody2D.constraints = value ? RigidbodyConstraints2D.FreezeRotation : (RigidbodyConstraints2D.FreezeRotation | RigidbodyConstraints2D.FreezePositionX);
                gameObject.layer = LayerMask.NameToLayer(value ? "Default" : "Ground");

                foreach (SpriteRenderer _SpriteRenderer in m_SpriteRenderers)
                    _SpriteRenderer.color = value ? Color.white : Color.blue;

                m_SpriteRenderers[(int)PhoneParts.Wifi].color = new Color(1, 1, 1, value ? 1 : 0);
            }
        }
        #endregion

        #region Unity Functions
        void Start()
        {
            m_NormalScale = m_SpritePartParentTransform.localScale;
        }

        void Update()
        {
            BoxCastChecking();
            BoxCastToObjectChecking();

            if (SetSelected)
                UpdateSineWaveManipuation();
        }
        #endregion

        #region Functions
        public void ControllableFunctions()
        {
            MovementAndJump();
            ControlTransmissions();
        }

        float SineWaveCalculated
        {
            get
            {
                return Mathf.Sin(m_SineTime * m_SineWaveManipulation.x) * m_SineWaveManipulation.y;
            }
        }

        public void InitiatePhoneUnit(int _SetID)
        {
            SetSelected = (_SetID == 0);
            m_UnitID = _SetID;

            m_ParticleSystem.emissionRate = 0;
            m_SineTime = Random.Range(-15f, 15f);
            UpdateSineWaveManipuation(true);
        }

        void UpdateSineWaveManipuation(bool _ToNormalize = false)
        {
            if (!_ToNormalize)
                m_SineTime += Time.deltaTime * m_SineWaveManipulation.z;

            m_SpriteRenderers[(int)PhoneParts.Head].transform.eulerAngles = new Vector3(0, 0, SineWaveCalculated);

            float _NormalTailScale = 0.9896458f + ( Mathf.Abs(SineWaveCalculated)/15);
            m_SpriteRenderers[(int)PhoneParts.Tail].transform.localScale = new Vector2(_NormalTailScale, _NormalTailScale);
        }

        void ControlTransmissions()
        {
            if (Input.GetMouseButton(1))
            {
                bool _hasAttract = false;

                foreach (TransmissionObject _Transmission in GameplayController.instance.CurrentTransmissions)
                {
                    if (!_Transmission.IsLocked)
                    {
                        _Transmission.ComeToUnit(transform.position);
                        _hasAttract = true;
                    }
                }

                if (_hasAttract)
                    GameController.instance.PlaySound(SFX.TransmissionAttract, 0.5f);
            }
        }

        void BoxCastToObjectChecking()
        {
            RaycastHit2D _CheckHit = (Physics2D.BoxCast(transform.position, m_BoxCollider2D.bounds.size, 0, Vector2.zero, 0, 1 << LayerMask.NameToLayer("Overlapping") | 1 << LayerMask.NameToLayer("Pickup")));

            if (_CheckHit.collider != null)
            {
                switch (_CheckHit.collider.tag)
                {
                    case "CollectForEnd":
                        _CheckHit.collider.gameObject.SetActive(false);

                        GameController.instance.PlaySound(SFX.GetMessage);
                        ObjectPooler.instance.CreateObject(PooledObjectsEnum.MessageGetParticle, _CheckHit.transform.position, Quaternion.identity);

                        GameplayController.instance.EndItemCollected();
                        break;
                    case "Transmission": case "Interference": case "BluetoothDoor":
                        GameplayController.instance.PhoneUnitHarmed(_isInterence: _CheckHit.collider.CompareTag("Interference"), _PassPhoneUnit: m_UnitID);
                        break;
                }
            }
        }

        public void MovementAndJump()
        {
            //Move Left and Right
            m_Rigidbody2D.velocity = new Vector2((Input.GetAxisRaw("Horizontal") == 1 || Input.GetAxisRaw("Horizontal") == -1) ? Input.GetAxisRaw("Horizontal") * m_MoveSpeed : 0, m_Rigidbody2D.velocity.y);

            //For Animations
            if (Input.GetAxisRaw("Horizontal") == 1)
            {
                m_ParticleSystem.emissionRate = 12.5f;
                m_SpritePartParentTransform.localScale = new Vector2(m_NormalScale.x, m_NormalScale.y);
            }
            else if (Input.GetAxisRaw("Horizontal") == -1)
            {
                m_ParticleSystem.emissionRate = 12.5f;
                m_SpritePartParentTransform.localScale = new Vector2(-m_NormalScale.x, m_NormalScale.y);
            }
            else
                m_ParticleSystem.emissionRate = 0;

            //Jumping
            if (Input.GetButtonDown("Jump") && m_onGround && !m_onCeiling)
            {
                m_Rigidbody2D.velocity = new Vector2(m_Rigidbody2D.velocity.x, m_JumpForce);
                GameController.instance.PlaySound(SFX.UnitJump, 0.85f);
                StartCoroutine("HoldJumpSequence");
            }
        }

        void BoxCastChecking()
        {
            //Detect wether on Ceiling and on Ground
            m_onGround = (Physics2D.BoxCast((Vector2)m_BoxCollider2D.bounds.center - new Vector2(0, m_BoxCollider2D.bounds.extents.y), new Vector2(m_BoxCollider2D.bounds.extents.x * 2, 0.15f), 0, Vector2.zero, 0, 1 << LayerMask.NameToLayer("Ground")));

            m_onCeiling = (Physics2D.BoxCast((Vector2)m_BoxCollider2D.bounds.center + new Vector2(0, m_BoxCollider2D.bounds.extents.y), new Vector2(m_BoxCollider2D.bounds.extents.x * 2, 0.15f), 0, Vector2.zero, 0, 1 << LayerMask.NameToLayer("Ground")));
        }

        IEnumerator HoldJumpSequence()
        {
            yield return new WaitForFixedUpdate();

            while (Input.GetButton("Jump") && !m_onCeiling && m_Rigidbody2D.velocity.y > 0 && m_Rigidbody2D.velocity.y < m_MaxJumpForce)
            {
                yield return new WaitForFixedUpdate();
                m_Rigidbody2D.velocity = new Vector2(m_Rigidbody2D.velocity.x, m_Rigidbody2D.velocity.y + m_additionalJumpForce);
            }

            yield return null;
        }
        #endregion

        #if UNITY_EDITOR
        void OnDrawGizmos()
        {
            //Ground
            Gizmos.color = m_onGround ? Color.red : Color.cyan;
            Gizmos.DrawWireCube((Vector2)m_BoxCollider2D.bounds.center - new Vector2(0, m_BoxCollider2D.bounds.extents.y), new Vector2(m_BoxCollider2D.bounds.extents.x * 2, 0.15f));

            //Ceiling
            Gizmos.color = m_onCeiling ? Color.red : Color.cyan;
            Gizmos.DrawWireCube((Vector2)m_BoxCollider2D.bounds.center + new Vector2(0, m_BoxCollider2D.bounds.extents.y), new Vector2(m_BoxCollider2D.bounds.extents.x * 2, 0.15f));

            //Player
            Gizmos.color = Color.white;
            Gizmos.DrawWireCube(transform.position, m_BoxCollider2D.bounds.size);
        }
        #endif
    }
}