using System.Collections.Generic;
using UnityEngine;
using UnityEngine.EventSystems;
using Valve.VR;
using Valve.VR.Extras;
using Valve.VR.InteractionSystem;

public class FurnitureMover : MonoBehaviour
{
    private SteamVR_LaserPointer steamVrLaserPointer;
    Transform previousContact = null;

    public SteamVR_Behaviour_Pose pose;
    public SteamVR_Action_Boolean interactWithUI = SteamVR_Input.GetBooleanAction("InteractUI");

    public SteamVR_Action_Boolean snapLeftAction = SteamVR_Input.GetBooleanAction("SnapTurnLeft");
    public SteamVR_Action_Boolean snapRightAction = SteamVR_Input.GetBooleanAction("SnapTurnRight");

    public LayerMask AutoPlacementEnvironmentMask;

    public GameObject pointer;
    public MovableFurniture Grabbing;

    public Color color;
    public float thickness = 0.002f;
    public Color clickColor = Color.green;

    private SnapTurn _snapturn;
    private Hand hand;
    private SnapTurn snapturn
    {
        get
        {
            if (_snapturn == null)
            {
                _snapturn = Player.instance.GetComponentInChildren<SnapTurn>();
            }
            return _snapturn;
        }
    }
    private void Start()
    {
        hand = GetComponent<Hand>();
        if (pose == null)
            pose = this.GetComponent<SteamVR_Behaviour_Pose>();
        if (pose == null)
            Debug.LogError("No SteamVR_Behaviour_Pose component found on this object", this);

        if (interactWithUI == null)
            Debug.LogError("No ui interaction action has been set on this component.", this);


        pointer = GameObject.CreatePrimitive(PrimitiveType.Cube);
        pointer.transform.parent = this.transform;
        pointer.transform.localScale = new Vector3(thickness, thickness, 100f);
        pointer.transform.localPosition = new Vector3(0f, 0f, 50f);
        pointer.transform.localRotation = Quaternion.identity;
        BoxCollider collider = pointer.GetComponent<BoxCollider>();
        if (collider)
        {
            Destroy(collider);
        }
        Material newMaterial = new Material(Shader.Find("Unlit/Color"));
        newMaterial.SetColor("_Color", color);
        pointer.GetComponent<MeshRenderer>().material = newMaterial;
    }
    private void Awake()
    {

    }

    private void Update()
    {
        float dist = 100f;
        Ray raycast = new Ray(transform.position, transform.forward);
        RaycastHit hit;
        bool bHit = Physics.Raycast(raycast, out hit);


        Ray SnapRaycast = new Ray(transform.position, transform.forward);
        RaycastHit SnapHit;
        bool SnapbHit = Physics.Raycast(SnapRaycast, out SnapHit, 100f, AutoPlacementEnvironmentMask);

        if (SnapbHit && Grabbing != null)
        {
            Grabbing.SnapTo(SnapHit.point, AutoPlacementEnvironmentMask, transform.forward);
        }
        
        if (previousContact && previousContact != hit.transform)
        {
            PointerEventArgs args = new PointerEventArgs();
            args.fromInputSource = pose.inputSource;
            args.distance = 0f;
            args.flags = 0;
            args.target = previousContact;
            OnPointerOut(this, args);
            previousContact = null;
        }
        if (bHit && previousContact != hit.transform)
        {
            PointerEventArgs argsIn = new PointerEventArgs();
            argsIn.fromInputSource = pose.inputSource;
            argsIn.distance = hit.distance;
            argsIn.flags = 0;
            argsIn.target = hit.transform;
            OnPointerIn(this, argsIn);
            previousContact = hit.transform;
        }
        if (!bHit)
        {
            previousContact = null;
        }
        if (bHit && hit.distance < 100f)
        {
            dist = hit.distance;
        }
        if (bHit && interactWithUI.GetStateDown(pose.inputSource))
        {
            PointerEventArgs argsClick = new PointerEventArgs();
            argsClick.fromInputSource = pose.inputSource;
            argsClick.distance = hit.distance;
            argsClick.flags = 0;
            argsClick.target = hit.transform;
            OnPointerClickDown(this, argsClick);
        }
        if (bHit && interactWithUI.GetStateUp(pose.inputSource))
        {
            PointerEventArgs argsClick = new PointerEventArgs();
            argsClick.fromInputSource = pose.inputSource;
            argsClick.distance = hit.distance;
            argsClick.flags = 0;
            argsClick.target = hit.transform;
            OnPointerClickUp(this, argsClick);
        }

        if (interactWithUI != null && interactWithUI.GetState(pose.inputSource))
        {
            pointer.transform.localScale = new Vector3(thickness * 5f, thickness * 5f, dist);
            pointer.GetComponent<MeshRenderer>().material.color = clickColor;
        }
        else
        {
            pointer.transform.localScale = new Vector3(thickness, thickness, dist);
            pointer.GetComponent<MeshRenderer>().material.color = color;
        }
        pointer.transform.localPosition = new Vector3(0f, 0f, dist / 2f);




        if(Grabbing != null && snapLeftAction != null && snapRightAction != null && snapLeftAction.activeBinding && snapRightAction.activeBinding)
        {
            
            bool leftHandTurnLeft = snapLeftAction.GetStateDown(hand.handType);
            bool rightHandTurnLeft = snapLeftAction.GetStateDown(hand.otherHand.handType);

            bool leftHandTurnRight = snapRightAction.GetStateDown(hand.handType);
            bool rightHandTurnRight = snapRightAction.GetStateDown(hand.otherHand.handType);

            if (leftHandTurnLeft || rightHandTurnLeft)
            {
                RotateObject(-45);
            }
            else if (leftHandTurnRight || rightHandTurnRight)
            {
                RotateObject(45);
            }
        }
    }

    private void RotateObject(float angle)
    {
        Grabbing.gameObject.transform.eulerAngles += new Vector3(0, angle, 0);
    }

    public void GrabFurniture(GameObject furniture)
    {
        //Catalog.Instance.GrabObject(furniture, gameObject.GetComponent<Hand>());
    }

    public void ReleaseFurniture(GameObject furniture)
    {
        Catalog.Instance.ReleaseObject(furniture, gameObject.GetComponent<Hand>());
    }
    private void OnPointerClickDown(object sender, PointerEventArgs e)
    {
        if (Grabbing)
        {
            return;
        }
        MovableFurniturePart clickHandler = e.target.GetComponent<MovableFurniturePart>();
        if (clickHandler == null)
        {
            return;
        }
        clickHandler.OnPointerClickDown();
        SetGrabbing(clickHandler.parent);
        GrabFurniture(Grabbing.gameObject);
        /*Grabbing.transform.SetParent(this.transform);*/
    }
    
    public void SetGrabbing(MovableFurniture furniture)
    {
        Grabbing = furniture;
        snapturn.enabled = false;
    }

    public void StopGrabbing()
    {
        if (Grabbing != null)
        {
            Grabbing.OnPointerClickUp();
            /*Grabbing.transform.SetParent(this.transform.root);*/
            Grabbing = null;
            snapturn.enabled = true;
        }
    }

    private void OnPointerClickUp(object sender, PointerEventArgs e)
    {
        StopGrabbing();
    }

    private void OnPointerOut(object sender, PointerEventArgs e)
    {
        MovableFurniturePart pointerExitHandler = e.target.GetComponent<MovableFurniturePart>();
        if (pointerExitHandler == null)
        {
            return;
        }

        pointerExitHandler.OnPointerExit();
    }

    private void OnPointerIn(object sender, PointerEventArgs e)
    {
        MovableFurniturePart pointerEnterHandler = e.target.GetComponent<MovableFurniturePart>();
        if (pointerEnterHandler == null)
        {
            return;
        }


        pointerEnterHandler.OnPointerEnter();
    }
}