using System.Collections;
using UnityEngine;
using UnityEngine.Events;
using UnityEngine.EventSystems;

public class WorldItemSelector : MonoBehaviour
{
    public float moveThreshold = 10;
    public LayerMask layerMask;
    public LayerMask gndMask;

    public void SelectScreenPoint(Vector2 screenPoint){
        Ray ray = Camera.main.ScreenPointToRay(screenPoint);
        RaycastHit hit = new RaycastHit();

        if(Physics.Raycast(ray,out hit, Mathf.Infinity, layerMask)){
            Building selectedB = hit.collider.GetComponent<Building>();
//            if(selectedB!=null){
//                Debug.Log("Selected building : " + selectedB.buildingData.buildingName);
//
//            }else{
//                Debug.Log("No target here, Unselecting");
//                //Selector.selectBuilding(null);
//            }
            Selector.selectBuilding(selectedB);

            if(Selector.insideHall){
                HumanInteractor interactor = hit.collider.GetComponent<HumanInteractor>();
                Selector.selectHuman(interactor);

                WorldspaceButton button = hit.collider.GetComponent<WorldspaceButton>();
                if(button!=null){
                    button.Click();
                }
            }
        }else{
            Selector.selectBuilding(null);
        }


    }

    public Vector3? GetTouchingWorldPoint(Vector2 screenPoint){
        Ray ray = Camera.main.ScreenPointToRay(screenPoint);
        RaycastHit hit = new RaycastHit();

        if(Physics.Raycast(ray,out hit, Mathf.Infinity, gndMask)){
            return hit.point;
        }else{
            return null;
        }
    }



    private Vector2? startedPos= null;
    private bool isPointerDown => startedPos!=null;
    private bool holdingPointer = false;
    public float dragDelay = 0.85f;
    private long pointerDownTimestamp;
    public void OnPointerDown(BaseEventData e){
        PointerEventData ped = (PointerEventData) e as PointerEventData;
        startedPos = ped.position;
        holdingPointer =true;
        Debug.Log($"Pointer timestamp : {pointerDownTimestamp}");
        StartCoroutine(startDragCheck());
    }

    IEnumerator startDragCheck(){
        yield return new WaitForSeconds(dragDelay);

        if(holdingPointer){
            Debug.Log("Initiating Drag");
            SelectScreenPoint(startedPos ?? Vector2.zero);

            Selector.setMoving(Selector.selectedBuilding);
        }
    }

    public void OnPointerMove(BaseEventData e){
        PointerEventData ped = (PointerEventData) e as PointerEventData;

        if(isPointerDown){

            float pointerDiff = Mathf.Abs(ped.position.magnitude - (startedPos ?? Vector2.zero).magnitude);

            holdingPointer=(pointerDiff < moveThreshold);

            if(Selector.isMovingBuilding){
            //    Debug.Log("Gnd position: " + GetTouchingWorldPoint(ped.position));
                Vector3 worldPos = GetTouchingWorldPoint(ped.position) ?? Selector.movingBuilding.transform.position;
                //validatePoint
                Selector.movingPointValid = true;
                Collider[] buildingsInside = Physics.OverlapBox(Selector.movingBuilding.GetComponent<Collider>().bounds.center, Selector.movingBuilding.GetComponent<Collider>().bounds.extents);
                foreach(Collider collider in buildingsInside){
                    if((collider.tag == "Building" || collider.tag == "Obstacle" ) && collider.transform != Selector.movingBuilding.transform){
                        Selector.movingPointValid =false;
                    }
                }
                Selector.movingBuilding.ChangeOutlineColor(Selector.movingPointValid  ? Color.green : Color.red);
                Selector.movingBuilding.transform.position = worldPos;
            }
        }
    }

    public void OnPointerUp(BaseEventData e){

        Selector.resetMoving();
        PointerEventData ped = (PointerEventData) e as PointerEventData;
        float pointerDiff = Mathf.Abs(ped.position.magnitude - (startedPos ?? Vector2.zero).magnitude);
        if(pointerDiff < moveThreshold){
            SelectScreenPoint(ped.position);
        }else{
           // Debug.Log("Pointer moved (" + pointerDiff+ "), Not gonna select item");
        }
        startedPos = null;
        holdingPointer=false;
        Selector.refresh();
    }
}

public static class Selector{
    //public static bool enabled=true;
    public static bool insideHall = false;
    public static bool movingPointValid;
    public static Building movingBuilding;
    public static bool isMovingBuilding => movingBuilding!=null;
    public static Building selectedBuilding;
    public static BuildingData selectedData => selectedBuilding.buildingData;

    public static HumanInteractor selectedHuman;
    public static UnityEvent OnSelectedChanged = new UnityEvent();

    public static void selectBuilding(Building e){
        selectedBuilding = e;
        if(insideHall){selectedBuilding=null;}
        OnSelectedChanged.Invoke();
    }

    public static void selectHuman(HumanInteractor e){
        selectedHuman = e;
        if(!insideHall){selectedHuman=null;}
        OnSelectedChanged.Invoke();
    }

    public static void resetMoving(){
        if(movingBuilding!=null ){
            if(movingPointValid) {
                DBmanager.RelocateBuilding(movingBuilding.buildingData.buildingName, movingBuilding.transform.position);
            }else{
                movingBuilding.transform.position = movingStartedPosition;
            }
        }
        movingBuilding=null;
        refresh();
    }

    private static Vector3 movingStartedPosition;

    public static void setMoving(Building e){
        movingBuilding=e;
        if(e!=null){ movingStartedPosition=e.transform.position;}
        refresh();
    }

    public static void refresh(){
        OnSelectedChanged.Invoke();
    }
}
