using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.InputSystem.HID;
using static UnityEditor.ShaderGraph.Internal.KeywordDependentCollection;

public class MoveController : MonoBehaviour
{
    public PlayerInputComponent playerInput;
    public Transform camRoot;
    public float jumpHeight = 2.0f;
    public float gravity = -13.524f;

    private int groundLayer = ~(1 << 6);
    private float speed = 5f;
    private float verticalVelocity = 0.0f;
    private float angleX;
    private float angleY;
    private float jumpInterval = 0.5f;
    private float jumpTime = 0.5f;
    private float oriDistance;
    private bool isGrounded = false;
    private bool hasLand = false;

    private AnimatorController controller;
    private Transform head;
    private Transform m_camera;
    private Vector3 move;
    private Vector3 gravityMove;
    private Vector3 lastMove;
    private Vector3 camInitPos;

    public enum PlayerState
    {
        Ground,
        JumpUp,
        JumpDown,
    }

    private CharacterController character;
    public PlayerState state;

    // Start is called before the first frame update
    void Start()
    {
        controller = GetComponent<AnimatorController>();
        character = GetComponent<CharacterController>();
        playerInput=GetComponent<PlayerInputComponent>();
        angleX = Vector3.Angle(Vector3.right, camRoot.right);
        angleY = Vector3.Angle(Vector3.up, camRoot.up);
        character.enabled = true;
        head = transform.Find("Head");
        m_camera = camRoot.transform.Find("Main Camera");
        camInitPos = m_camera.localPosition;
        oriDistance = Vector3.Distance(head.position, m_camera.position-m_camera.forward*2);
    }

    // Update is called once per frame
    void Update()
    {
        if (StepManager.isFaceBuidling)
            playerInput.InputReset();
        CharacterMovement();
    }

    /// <summary>
    /// ��ɫ�ƶ���ת���߼�
    /// </summary>
    void CharacterMovement()
    {
        if (hasLand)
        {
            jumpTime += Time.deltaTime;
        }
        // ����Ƿ��ڵ�����
        //isGrounded = IsGrounded();
        isGrounded =character.isGrounded|| IsGrounded();
        if (isGrounded && state == PlayerState.JumpDown)
        {
            verticalVelocity = 0;
            state = PlayerState.Ground;
            hasLand = true;
        }
        //Debug.Log(isGrounded);
        if (state == PlayerState.Ground)
        {
            // ���¿ո��������Ծ
            if (playerInput.JumpInput)
            {
                //state = PlayerState.JumpUp;
                //Jump();
                //controller.jump = true;
                //jumpTime = 0;
                //hasLand = false;

                if (jumpTime >= jumpInterval)
                {
                    state = PlayerState.JumpUp;
                    Jump();
                    controller.jump = true;
                    jumpTime = 0;
                    hasLand = false;
                }
            }
        }
        if (!isGrounded && state != PlayerState.JumpUp)
        {
            state = PlayerState.JumpDown;
        }

        move = Vector3.zero;
        if (state != PlayerState.Ground)
        {
            // Ӧ������
            ApplyGravity();
        }
        else
        {
            gravityMove = new Vector3(0, 0, 0);
        }
        move +=
            new Vector3(playerInput.MoveInput.x, 0, playerInput.MoveInput.y)
            * Time.deltaTime
            * speed;

        // �ƶ�����
        Move();
        UpdateControlRotation();
    }

    void Jump()
    {
        // ������Ծ�ٶ��Դﵽָ������Ծ�߶�
        verticalVelocity = Mathf.Sqrt(-2.0f * gravity * jumpHeight);
    }

    void ApplyGravity()
    {
        // Ӧ��������ģ������Ĵ�ֱ�˶�
        verticalVelocity += gravity * Time.deltaTime;
        // ���ݴ�ֱ�ٶ��ƶ�����
        if (verticalVelocity < 0.1f && verticalVelocity > -0.1f && state == PlayerState.JumpUp)
        {
            //Debug.Log("*************");
            state = PlayerState.JumpDown;
        }

        //Debug.Log(verticalVelocity * 100);
        gravityMove = new Vector3(0, verticalVelocity * Time.deltaTime, 0);
    }

    void Move()
    {
        CameraLimitation();

        if (playerInput.MoveInput != Vector2.zero)
        {
            Vector3 dir = Vector3.zero;

            //Debug.Log(playerInput.MoveInput);
            if (playerInput.MoveInput.x > 0)
            {
                dir = Vector3.ProjectOnPlane(camRoot.right, Vector3.up);
            }
            if (playerInput.MoveInput.x < 0)
            {
                dir += Vector3.ProjectOnPlane(-camRoot.right, Vector3.up);
            }
            if (playerInput.MoveInput.y > 0)
            {
                dir += Vector3.ProjectOnPlane(camRoot.forward, Vector3.up);
            }
            if (playerInput.MoveInput.y < 0)
            {
                dir += Vector3.ProjectOnPlane(-camRoot.forward, Vector3.up);
            }
            //Debug.Log(dir);
            Vector3 targetDir = Vector3.RotateTowards(
                transform.forward,
                //camera.forward.ProjectOntoPlane(Vector3.up),
                dir,
                10,
                0f
            );
            transform.rotation = Quaternion.Slerp(
                transform.rotation,
                Quaternion.LookRotation(targetDir),
                Time.deltaTime * 15f
            );
            //var a = Vector3.Angle(transform.forward.normalized, playerInput.MoveInput.normalized);
            //Quaternion r = Quaternion.Euler(0, a, 0);
            //transform.eulerAngles = r * transform.eulerAngles;
        }
        //var m = move.magnitude * camera.forward + gravityMove;
        //Debug.Log(move + "*******" + "************" + m);
        var angle = AngleSigned(
            Vector3.forward,
            Vector3.ProjectOnPlane(camRoot.forward, Vector3.up),
        transform.up
        );
        Quaternion rot = Quaternion.Euler(0, angle, 0);
        //Vector3 move2 = camera.transform.TransformDirection(move);


        //Debug.Log(move.magnitude + "***********" + gravityMove.magnitude);

        //var m = move * 0.1f + lastMove * 0.9f;
        var rm = rot * move;
        if (gravityMove != Vector3.zero)
        {
            rm *= 2.5f;
        }

        rm = rm * 0.1f + lastMove * 0.9f;

        //if (state == PlayerState.JumpDown)
        //{
        //    character.Move(-colliderDir * Time.deltaTime);
        //}

        character.Move(rm + gravityMove);
        lastMove = rm;
        controller.speed = rm.magnitude * 300;
        camRoot.position = character.transform.position + new Vector3(0, 1.148f, 0);
    }

    public static float AngleSigned(Vector3 v1, Vector3 v2, Vector3 n)
    {
        return Mathf.Atan2(Vector3.Dot(n, Vector3.Cross(v1, v2)), Vector3.Dot(v1, v2))
            * Mathf.Rad2Deg;
    }

    private Vector3 pointBottom;
    private Vector3 pointTop;
    private float radius = 0.5f;
    private Collider[] colliders;

    bool IsGrounded()
    {
        // �������������Ӽ�������Ƿ��ڵ����ϵ��߼�
        // �������߼�⡢��ײ������
        var pos = transform.position;
        radius = character.radius * 0.9f;
        pointBottom = pos + transform.up * radius - transform.up * 0.1f;
        pointTop = pos + transform.up * character.height - transform.up * radius;

        colliders = Physics.OverlapCapsule(pointBottom, pointTop, radius, groundLayer);
        Debug.DrawLine(pointBottom, pointTop, Color.red);
        if (colliders.Length != 0)
        {
            return true;
        }
        else
        {
            return false;
        }
    }

    private void UpdateControlRotation()
    {
        if (
            playerInput.touch0Input != Vector2.zero
            && playerInput.MoveInput == Vector2.zero
            && !EventSystem.current.IsPointerOverGameObject()
        )
        {
            //camera.eulerAngles += (new Vector3(playerInput.touch0Input.y, playerInput.touch0Input.x, 0)) * 0.1f;
            angleX += playerInput.touch0Input.x * 10 * Time.fixedDeltaTime;
            angleY -= playerInput.touch0Input.y * 10 * Time.fixedDeltaTime;
            angleY = angleClamp(angleY, -45, 60);//�����ת�Ƕ�����

            //ʹ�ò�ֵƽ����ת
            camRoot.rotation = Quaternion.Lerp(camRoot.rotation, Quaternion.Euler(angleY, angleX, 0), Time.fixedDeltaTime * 100);

        }
        if (
            playerInput.touch1Input != Vector2.zero
            && !EventSystem.current.IsPointerOverGameObject()
        )
        {
            angleX += playerInput.touch1Input.x * 10 * Time.fixedDeltaTime;
            angleY -= playerInput.touch1Input.y * 10 * Time.fixedDeltaTime;
            angleY = angleClamp(angleY, -45, 60);//�����ת�Ƕ�����

            //ʹ�ò�ֵƽ����ת
            camRoot.rotation = Quaternion.Lerp(camRoot.rotation, Quaternion.Euler(angleY, angleX, 0), Time.fixedDeltaTime * 100);
        }

        angleX += playerInput.CameraInput.x * 10 * Time.fixedDeltaTime;
        angleY -= playerInput.CameraInput.y * 10 * Time.fixedDeltaTime;
        angleY = angleClamp(angleY, -45, 60);//�����ת�Ƕ�����

        //ʹ�ò�ֵƽ����ת
        camRoot.rotation = Quaternion.Lerp(camRoot.rotation, Quaternion.Euler(angleY, angleX, 0), Time.fixedDeltaTime * 10);
    }

    private static float angleClamp(float angle, float min, float max)
    { //һ�����ƽǶ������Сֵ�ķ���
        if (angle < -360)
            angle += 360;
        if (angle > 360)
            angle -= 360;
        return Mathf.Clamp(angle, min, max);
    }

    /// <summary>
    /// �����˳ƾ�ͷ�����ƶ�
    /// </summary>
    private void CameraLimitation()
    {
        float cosAngle = Vector3.Dot(m_camera.forward, Vector3.up);
        float angleRad = Mathf.Asin(cosAngle);
        float angleDeg = Mathf.Rad2Deg * angleRad;
        float sign = Mathf.Sign(Vector3.Dot(Vector3.Cross(m_camera.forward, Vector3.up), Vector3.up));
        float finalAngle = sign * angleDeg;
        //float moveDistance = Mathf.Sin(Mathf.Deg2Rad * Mathf.Clamp(finalAngle, 0f, 10)) * 2;
        float z, obsDistance = 0, camDistance = 0;
        //Debug.Log(finalAngle);

        //射线检测是否有障碍物
        Ray ray = new Ray(head.position, m_camera.position - head.position);

        RaycastHit[] temphit;
        RaycastHit hit;
        var cos = Physics.Raycast(ray, out hit, oriDistance, ~(1 << 6|1<<18));
        if (cos)
        {

            Debug.Log(hit.collider.name);
            m_camera.position = Vector3.Lerp(m_camera.position, hit.point, 0.5f);

        }
        else
        {

            m_camera.localPosition = Vector3.Lerp(m_camera.localPosition, camInitPos, 0.5f);

        }




        //RaycastHit[] temphit;
        //var cos = Physics.RaycastAll(head.position, m_camera.position - head.position, oriDistance, ~(1 << 6));
        //if (cos.Length>0)
        //{
        //    //Debug.Log(temphit.collider.name);
        //    //m_camera.position = Vector3.Lerp(m_camera.position, temphit.point, 0.5f);
        //    RaycastHit hit = cos[0];
        //    float dis = 0;
        //    for (int i = 1; i<cos.Length; i++)
        //    {
        //        if(dis< Vector3.Distance(cos[i].point, head.position))
        //        {
        //            dis = Vector3.Distance(cos[i].point, head.position);
        //            hit = cos[i];

        //        }
        //    }
        //    if(!hit.collider.name.Contains("Main"))
        //    {
        //        Debug.Log(hit.collider.name);
        //        m_camera.position = Vector3.Lerp(m_camera.position, hit.point, 0.5f);
        //    }


        //    //if (temphit.collider.name != "Main Camera")
        //    //{

        //    //}
        //    //else
        //    //{
        //    //    //如果射线没有打到任何collider,或者打到的不是墙体,则将相机和角色之间的距离还原
        //    //    Vector3 p = (m_camera.position - head.position).normalized * oriDistance;
        //    //    Vector3 newPoint = head.position + p;
        //    //    m_camera.position = Vector3.Lerp(m_camera.position, newPoint, 0.5f);
        //    //}
        //}
        //else
        //{

        //    m_camera.localPosition = Vector3.Lerp(m_camera.localPosition, camInitPos, 0.5f);

        //}



        //else
        //{
        //    //如果射线没有打到任何collider,或者打到的不是墙体,则将相机和角色之间的距离还原
        //    Vector3 p = (m_camera.position - head.position).normalized * oriDistance;
        //    Vector3 newPoint = head.position + p;
        //    m_camera.localPosition = Vector3.Lerp(m_camera.position, new Vector3(0,1.48f,-5), 0.5f);
        //}
        //  

        //}

        //if (isBlock)
        //{
        ////������ת��ͷ����
        //if (finalAngle > 1)
        //{
        //    z = finalAngle * 0.1f;
        //    camDistance = Vector3.Distance(camInitPos + new Vector3(0, 0, z),head.position);
        //    Debug.DrawLine(temphit.point, head.position, Color.red);
        //    Debug.DrawLine(camInitPos + new Vector3(0, 0, z), head.position, Color.blue);
        //    Debug.Log(hit.collider.name+"))"+obsDistance + " // " + camDistance);
        //    //if (obsDistance < camDistance && obsDistance > 0)
        //    //{
        //    //    m_camera.position = Vector3.Lerp(m_camera.position, hit.point, 0.1f);
        //    //}
        //    //else
        //    //{
        //    //    m_camera.localPosition = camInitPos + new Vector3(0, 0, z);
        //    //}

        //}
        //else
        //    {
        //        m_camera.position = Vector3.Lerp(m_camera.position, hit.point, 0.5f);
        //    }
        //}
        //else
        //{
        //旋转
        if (finalAngle > 1)
        {
            z = finalAngle * 0.1f;
            var pos = camInitPos + new Vector3(0, 0, z);
            var dis1 =Vector3.Distance(head.position, pos);
            var dis2 =Vector3.Distance(m_camera.position, head.position);
            if(!cos)
                m_camera.localPosition = camInitPos + new Vector3(0, 0, z);
        }


        if (m_camera.localPosition.z > -0.4f)
        {
            m_camera.localPosition = new Vector3(m_camera.localPosition.x, m_camera.localPosition.y,-0.4f);
        }
        //else
        //{
        //    m_camera.localPosition = Vector3.Lerp(m_camera.localPosition, camInitPos, 0.5f);
        //}
        //}
    }
}