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

[RequireComponent(typeof(CircleCollider2D))]
[RequireComponent(typeof(MouseInputBehaviour))]
[RequireComponent(typeof(Rigidbody2D))]
public class MouseController : MonoBehaviour
{
    // The sling shot speed modifier
    public float                slingSpeed = 1.0f;

    // The attraction factor for when the mouse hits the patch
    public float                attractionFactor = 50.0f;

    // The collider of the mouse
    private CircleCollider2D    circle2D;

    // The rigidbody of the mouse
    private new Rigidbody2D     rigidbody2D;

    // // Check if the mouse is hanging
    private bool                 isHanging;
    
    // The gravity of the rigidbody
    private float               gravity;
    
    // The patch that the mouse is hanging onto
    private GameObject          currentPatch;

    public GameObject m_CurrentCloth;
    public Vector3 m_ClothPosition;
    private Vector3 m_Velocity;

    public Animator m_MouseAnim;
    public bool m_IsFlying;
    public Rigidbody2D m_RB;
    public GameObject m_SpriteRoot;
    public GameObject m_MovementParticleLeft;
    public GameObject m_MovementParticleRight;

    public bool m_ContactPatch;

    public AudioSource m_EffectsPlayer;
    public AudioSource m_VoicePlayer;
    public AudioSource m_SoundPlayer;

    public AudioClip m_JumpingSound;
    public List<AudioClip> m_JumpVoiceSounds;

    public AudioClip m_StitchSound;
    public AudioClip m_GrabClothSound;
    public AudioClip m_FlyingSound;
    public AudioClip m_GrabPatchSound;
    public AudioClip m_DropSound;

    public float GravityScale
    {
        get
        {
            return gravity;
        }
    }

    public bool IsHanging
    {
        get
        {
            return isHanging;
        }
    }

    private void Awake()
    {
        currentPatch  = gameObject;
        circle2D   = gameObject.GetComponent<CircleCollider2D>();
        rigidbody2D     = gameObject.GetComponent<Rigidbody2D>();
        isHanging       = false;
        gravity         = rigidbody2D.gravityScale;
        
        // Register mouse input events
        gameObject.GetComponent<MouseInputBehaviour>().onDragFinishHandler += OnDragFinish;

        // Register patch events
        // DION YOUR CODE NEED DOUBLE CALL TO WORK?
        PatchBehaviour.onPatchHandler += OnPatch;
        PatchBehaviour.onPatchHandler += OnPatch;

        PatchBehaviour.onPatchExitHandler += OnPatchExit;
        PatchBehaviour.onPatchGgHandler += OnPatchGg;

        m_ClothPosition = transform.position;
    }

    public void Update()
    {
        if (isHanging)
        {
            m_MouseAnim.Play("Grab");

            m_MovementParticleLeft.SetActive(false);
            m_MovementParticleRight.SetActive(false);
        }
        else if (m_RB.velocity.y > 2)
        {
            m_MouseAnim.Play("Flying");

            if (m_RB.velocity.x > 0)
            {
                m_MovementParticleRight.SetActive(true);
                if (m_SpriteRoot.transform.localScale.x > 0)
                {
                    m_SpriteRoot.transform.localScale = new Vector3(m_SpriteRoot.transform.localScale.x * -1, m_SpriteRoot.transform.localScale.y, m_SpriteRoot.transform.localScale.z);
                }
            }
            else if (m_RB.velocity.x < 0)
            {
                m_MovementParticleLeft.SetActive(true);
                if (m_SpriteRoot.transform.localScale.x < 0)
                {
                    m_SpriteRoot.transform.localScale = new Vector3(m_SpriteRoot.transform.localScale.x * -1, m_SpriteRoot.transform.localScale.y, m_SpriteRoot.transform.localScale.z);
                }
            }
        }
    
        else
        {

            if (m_RB.velocity.x > 0)
            {
                m_MovementParticleRight.SetActive(true);
                if (m_SpriteRoot.transform.localScale.x > 0)
                {
                    m_SpriteRoot.transform.localScale = new Vector3(m_SpriteRoot.transform.localScale.x * -1, m_SpriteRoot.transform.localScale.y, m_SpriteRoot.transform.localScale.z);
                }
            }
            else if (m_RB.velocity.x < 0)
            {
                m_MovementParticleLeft.SetActive(true);
                if (m_SpriteRoot.transform.localScale.x < 0)
                {
                    m_SpriteRoot.transform.localScale = new Vector3(m_SpriteRoot.transform.localScale.x * -1, m_SpriteRoot.transform.localScale.y, m_SpriteRoot.transform.localScale.z);
                }
            }

            m_MouseAnim.Play("Falling");
        }


        if (m_CurrentCloth == null)
        {
            return;
        }
        else
        {
            if (Vector3.Distance(m_ClothPosition,transform.position) > 4)
            {
                m_ClothPosition = Vector3.SmoothDamp(m_ClothPosition, transform.position, ref m_Velocity, 0.75f);
            }
            else
            {
                Vector3 randValue = Random.onUnitSphere;
                randValue.z = 0;
                m_ClothPosition += randValue*Time.deltaTime;
            }
            
            m_CurrentCloth.transform.position = Vector3.Lerp(m_ClothPosition, m_CurrentCloth.transform.position,0.25f);
        }

        
    }

    private void OnDestroy()
    {
        // Deregister mouse input events
        gameObject.GetComponent<MouseInputBehaviour>().onDragFinishHandler -= OnDragFinish;

        // Unregister patch events
        PatchBehaviour.onPatchHandler -= OnPatch;
        PatchBehaviour.onPatchHandler -= OnPatch;
        PatchBehaviour.onPatchExitHandler -= OnPatchExit;
        PatchBehaviour.onPatchGgHandler -= OnPatchGg;
    }

    private void OnDragFinish(Vector2 delta)
    {
        // Check if the mouse is currently hanging
        if (isHanging)
        {
            m_ContactPatch = false;

            m_VoicePlayer.clip = m_JumpVoiceSounds[Random.Range(0,m_JumpVoiceSounds.Count)];
            m_VoicePlayer.Play();

            m_SoundPlayer.clip = m_FlyingSound;
            m_SoundPlayer.Play();

            m_EffectsPlayer.clip = m_JumpingSound;
            m_EffectsPlayer.Play();
            // Flip the drag
            delta = -delta;

            // Enable the gravity again
            rigidbody2D.gravityScale = gravity;

            // Add the force
            rigidbody2D.AddForce(delta * slingSpeed, ForceMode2D.Impulse);

            // Set is hanging as false
            isHanging = false;
        }
    }

    public void OnPatch(GameObject patch)
    {
        // Check if the mouse is currently hanging and if the patch is already visited
        if (!isHanging &&
            patch != currentPatch)
        {
            Vector2 patchCenter = new Vector2(patch.transform.position.x, patch.transform.position.y);

            if (!m_ContactPatch)
            {
                m_EffectsPlayer.clip = m_GrabPatchSound;
                m_EffectsPlayer.Play();
                m_ContactPatch = true;
            }
            // Get the direction from the mouse to the patch center
            Vector2 dir = patchCenter - new Vector2(transform.position.x, transform.position.y);

            // Check if mouse is at or near the center
            if (dir.magnitude < 0.1f)
            {
                // Mouse is at or near center, update relevant information
                transform.position = new Vector3(patchCenter.x, patchCenter.y, transform.position.z);

                isHanging = true;
                rigidbody2D.gravityScale = 0;
                rigidbody2D.velocity = Vector2.zero;
                currentPatch = patch;
            }
            else
            {
                // Mouse is not near center, keep moving towards center
                rigidbody2D.AddForce(dir * attractionFactor);
                rigidbody2D.velocity *= 0.8f;
            }
        }
    }

    public void OnPatchExit()
    {
        currentPatch = gameObject;
    }

    public void OnPatchGg(GameObject patch)
    {
        if (isHanging)
        {
            // Stop hanging
            isHanging = false;

            // Enable the gravity again
            rigidbody2D.gravityScale = gravity;
            m_SoundPlayer.clip = m_DropSound;
            m_SoundPlayer.Play();

        }
    }

    public void OnTriggerEnter2D(Collider2D collision)
    {
        if (isHanging) return;
        GrabbableCloth cloth = collision.GetComponent<GrabbableCloth>();
        if (cloth != null)
        {
            if (m_CurrentCloth != null)
            {
                if (m_CurrentCloth != collision.gameObject)
                {
                    GrabbableCloth prevCloth = m_CurrentCloth.GetComponent<GrabbableCloth>();
                    prevCloth.DestroyCloth();
                }
            }
            m_SoundPlayer.clip = m_GrabClothSound;
            m_SoundPlayer.Play();
            m_CurrentCloth = collision.gameObject;
            cloth.m_DisableCloth = true;
            cloth.m_Collider.enabled = false;
            m_ClothPosition = cloth.transform.position;

            cloth.Grabbed();
        }
    }
}
