using System.Collections;
using System.Collections.Generic;
using Mirror;
using UnityEngine;
using UnityEngine.Audio;
public class PlayerController : NetworkBehaviour
{
    public Rigidbody2D rigidbody;
    public SpriteRenderer sprite;
    public bool invertSprite;
    public Animator animator;
    public LayerMask groundLayerMask;
    // public float drownedDepth;
    public bool isGrounded = true;
    public bool isSwimming = false;
    public Transform groundChecker;
    public Vector2 gravity;
    public float buoyantForce;
    public float buoyantSpd;
    public float moveSpeed = 1;
    public float jumpForce = 10;
    public float jumpDuration = 0.2f;
    public AudioClip jumpSFX;
    float jumpT = 0;
    public bool listenToInput = true;
    public bool inDoor = false;
    public bool insideDoor = false;
    bool enteringDoor = false;

    void Start()
    {
        jumpT = jumpDuration;
    }

    bool _grounded = false;
    float moveInput = 0;
    bool jumpReleased = true;
    [HideInInspector]
    public bool inWater;
    void FixedUpdate()
    {
        isGrounded = getGrounded();

        if (_grounded != isGrounded)
        {
            if (isGrounded)
            {
                OnLand();
            }
            else
            {
                OnFly();
            }
            _grounded = isGrounded;
        }

        if (isSwimming)
        {
            rigidbody.velocity = new Vector2(rigidbody.velocity.x, Mathf.Lerp(rigidbody.velocity.y, buoyantForce, buoyantSpd));
            if ((Input.GetKey(InputManager.data().jumpInput)))
            {
                rigidbody.velocity = new Vector2(rigidbody.velocity.x, jumpForce / 12f);
            }
        }
        else
        {
            gravity = new Vector2(gravity.x, 0);
        }

        //Gravity Application
        rigidbody.AddForce(gravity);

        //Update In-Air value on animation
        animator.SetBool("inAir", !isGrounded);
        animator.SetBool("isOnWater", inWater);

        float HorizontalAxis = 0;
        if (Input.GetKey(InputManager.data().leftInput)) { HorizontalAxis = -1; } else if (Input.GetKey(InputManager.data().rightInput)) { HorizontalAxis = 1; }
        // if (GameManager.isPaused) { HorizontalAxis = 0; }
        //Move according to input

        //Exit the door
        if (enteringDoor && !Input.GetKey(InputManager.data().interactingKey))
        {
            enteringDoor = false;
        }
        if (insideDoor && !enteringDoor && Input.GetKey(InputManager.data().interactingKey))
        {
            Debug.Log("Exiting door");
            transform.position = SceneData.netSceneData.door.transform.position;
            insideDoor = false;
            enteringDoor = true;
            if (GetComponent<NetPlayer>() != null) { GetComponent<NetPlayer>().CallChangeInsideDoor(insideDoor); }
        }
        if (listenToInput)
        {
            if (isGrounded)
            {
                moveInput = HorizontalAxis;
            }
            else
            {
                //Change moveInput while in-air | IF there is an input
                if (Input.GetKey(InputManager.data().leftInput) || Input.GetKey(InputManager.data().rightInput))
                {
                    moveInput = Mathf.Lerp(moveInput, HorizontalAxis, 0.2f);
                }
            }

            //Enter the door
            if (inDoor && Input.GetKey(InputManager.data().interactingKey) && !enteringDoor)
            {
                if (SceneData.netSceneData.doorExit != null)
                {
                    Debug.Log("Entering door");
                    transform.position = SceneData.netSceneData.doorExit.position;
                    insideDoor = true;
                    enteringDoor = true;
                    if (GetComponent<NetPlayer>() != null) { GetComponent<NetPlayer>().CallChangeInsideDoor(insideDoor); }
                }
            }

        }

        if (isSwimming || inWater) { moveInput = moveInput / 2f; }
        //Update moving value on Animation
        animator.SetBool("moving", (moveInput != 0));
        animator.SetBool("isSwimming", isSwimming);
        //Flip Image to face moving Direction
        if (moveInput < 0)
        {
            sprite.flipX = (invertSprite) ? false : true;
        }
        else if (moveInput > 0)
        {
            sprite.flipX = (invertSprite) ? true : false;
        }




        //Apply moving input to player
        // if (GetComponent<NetPlayer>() != null)
        // {
        //     if (GetComponent<NetPlayer>().parentFrnd != null)
        //     {
        //         rigidbody.velocity = GetComponent<NetPlayer>().parentFrnd.GetComponent<Rigidbody2D>().velocity;
        //     }
        // }
        rigidbody.transform.Translate(new Vector2(moveSpeed * moveInput, 0));


        bool _canJump = canJump();
        if ((Input.GetKey(InputManager.data().jumpInput)) && _canJump)
        {
            jumpT = 0;
            jumpReleased = false;
            rigidbody.velocity = new Vector2(rigidbody.velocity.x, 0);
            if (jumpSFX != null) AudioSingleton.getSFXSource().PlayOneShot(jumpSFX);
        }


        //Blocks continous jump button
        if (!Input.GetKey(InputManager.data().jumpInput)) { jumpReleased = true; }

        //Apply Jump to player
        if (jumpT < jumpDuration)
        {
            jumpT += Time.deltaTime;
            float progress = (jumpDuration - jumpT) / jumpDuration;
            //|| jumpT < jumpDuration/2f 
            if ((Input.GetKey(InputManager.data().jumpInput)) || b) { rigidbody.AddForce(new Vector2(0, jumpForce * progress)); }
        }
        else { b = false; }

        _isSwimming = inWater;

    }

    bool b;
    bool _isSwimming;
    public bool waterBoost;
    public bool canJump()
    {
        return jumpT >= jumpDuration && isGrounded && listenToInput && jumpReleased && !isSwimming && transform.childCount <= 0;//&& !GameManager.isPaused
    }

    public bool canBotJump()
    {
        return isGrounded || isSwimming || inWater;
    }

    //External Player Control Exposure
    public void Jump()
    {
        jumpT = 0;
        rigidbody.velocity = new Vector2(rigidbody.velocity.x, 0);
        b = true;
        AudioSingleton.getSFXSource().PlayOneShot(jumpSFX);
    }
    public void move(float input)
    {
        input = Mathf.Clamp(input, -1, 1);

        moveInput = input;
    }


    void OnLand()
    {
        // Debug.Log("Landed Like a boss!");
    }

    void OnFly()
    {
        // Debug.Log("Hey look im flying");
    }
    public float groundCheckerDist = 0.1f;
    public float groundCheckerHeighMultipler = 1f;
    public bool getGrounded()
    {
        //return (Physics2D.Linecast(transform.position, groundChecker.position, groundLayerMask));
        Collider2D col = GetComponentInChildren<Collider2D>();
        return (Physics2D.BoxCast(col.bounds.center, new Vector2(col.bounds.size.x - (col.bounds.size.x / 5f), col.bounds.size.y * groundCheckerHeighMultipler), 0, Vector2.down, groundCheckerDist, groundLayerMask));
    }

    void OnDrawGizmos()
    {
        Collider2D col = GetComponentInChildren<Collider2D>();
        Gizmos.color = Color.red;
        Gizmos.DrawWireCube(col.bounds.center - new Vector3(0, groundCheckerDist), new Vector2(col.bounds.size.x - (col.bounds.size.x / 5f), col.bounds.size.y * groundCheckerHeighMultipler));
    }

    // public bool getInWater(){Collider2D col = GetComponentInChildren<Collider2D>();
    //     return (Physics2D.BoxCast(col.bounds.center, new Vector2(col.bounds.size.x - (col.bounds.size.x / 5f), col.bounds.size.y), 0, Vector2.down, 0.1f, waterLayerMask));
    // }


}


// public static class SettingsInstance{
//     public static Settings instance;

// }

public static class AudioSingleton
{
    private static AudioSource music;
    private static AudioSource sfx;

    public static AudioMixer mixer = Resources.Load("MasterMixer") as AudioMixer;
    public static AudioSource getMusicSource()
    {

        if (music == null)
        {
            GameObject go = new GameObject("Music Audio Source");
            go.AddComponent<AudioSource>();
            music = go.GetComponent<AudioSource>();
            music.outputAudioMixerGroup = mixer.FindMatchingGroups("Music")[0];
        }

        return music;
    }
    public static AudioSource getSFXSource()
    {
        //AudioMixer mixer = Resources.Load("MasterMixer") as AudioMixer;
        if (sfx == null)
        {
            GameObject go = new GameObject("SFX Audio Source");
            go.AddComponent<AudioSource>();
            sfx = go.GetComponent<AudioSource>();
            Debug.Log("sfx : " + (sfx == null).ToString() + ", mixer: " + (mixer == null).ToString());
            sfx.outputAudioMixerGroup = mixer.FindMatchingGroups("SFX")[0];
        }

        return sfx;
    }
}

