using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR.ARFoundation;
using UnityEngine.EventSystems;
using UnityEngine.XR.ARSubsystems;
using System;
using UnityEngine.XR.Interaction.Toolkit.AR;
using UnityEngine.SceneManagement;

using UnityEngine.Networking;
using System.Linq;

using ARLocation;

public class InputManager : ARBaseGestureInteractable
{
    public List<GameObject> arObjects;
    public Camera arCamera;
    public ARRaycastManager rayManager;
    public GameObject crosshair;
    //public ObjectPointsHolder points;

    private string selected;
    private GameObject selectedObject;

    List<ARRaycastHit> hits = new List<ARRaycastHit>();


    private Pose pose;

    // REAL WORLD STUFF

    public GameObject serverManager;
    private string playerNumber;
    public GameObject playerNumberObject;
    private string longitude;
    private string latitude;
    private float elapsed = 2.0f;
    private float period = 2.5f;

    public GameObject gpsPrefab;

    private string gameNumber;



    // Start is called before the first frame update
    void Start()
    {
        selected = "empty";
        selectedObject = arObjects[0];

        this.gameNumber = serverManager.GetComponent<CurrentGameConnect>().GetGameNumber();
        this.playerNumber = playerNumberObject.GetComponent<CurrentPlayerPicker>().GetPlayerNumber();

        longitude = "0";
        latitude = "0";

    }


   
    // Update is called once per frame
    void Update()
    {
        if (SceneManager.GetActiveScene().name != "RealWorld") 
        {
                return;
        }

        elapsed += Time.deltaTime;
        
        if (elapsed >= period) {
            elapsed = 0.0f;

            StartCoroutine(GetLocation());
        }

        
    }

    private void FixedUpdate()
    {
        CrossHairCalculation();
        
        
    }


    public void ChangeSelection(string selection)
    {
        this.selected = selection;

        foreach (GameObject obj in arObjects)
        {
            if (obj.name == selected)
            {
                this.selectedObject = obj;
            }
        }
    }

    private bool IsPointerOverUI(TapGesture touch)
    {
        PointerEventData eventData = new PointerEventData(EventSystem.current);
        eventData.position = new Vector2(touch.startPosition.x, touch.startPosition.y);

        List<RaycastResult> results = new List<RaycastResult>();

        EventSystem.current.RaycastAll(eventData, results);

        return results.Count > 0;
    }

    private void CrossHairCalculation()
    {
        Vector3 origin = arCamera.ViewportToScreenPoint(new Vector3(0.5f,0.5f,0));

        if (GestureTransformationUtility.Raycast(origin, hits, TrackableType.PlaneWithinPolygon))
        {
            pose = hits[0].pose;
            crosshair.transform.position = pose.position;
            crosshair.transform.eulerAngles = new Vector3(90, 0, 0);
        }

    }


    // OVERRIDES

    protected override bool CanStartManipulationForGesture(TapGesture gesture)
    {
        if(gesture.TargetObject == null)
        {
            return true;
        }
        return false;
    }

    protected override void OnEndManipulation(TapGesture gesture)
    {
        if (gesture.WasCancelled)
            return;

        if (gesture.TargetObject != null || IsPointerOverUI(gesture))
        {
            return;
        }

        if(isAnotherSelected())
        {
            return;
        }

        if(isDeleteVisible())
            return;
        
        
        if (GestureTransformationUtility.Raycast(gesture.startPosition, hits ,TrackableType.PlaneWithinPolygon))
        {
            
            
            // REAL WORLD GAME BLOCK

            if (SceneManager.GetActiveScene().name != "RealWorld") 
            {
                GameObject placedObject = Instantiate(selectedObject, pose.position, pose.rotation);
                return;
            }
            else 
            {
                //GameObject placedObject2 = Instantiate(selectedObject, pose.position, pose.rotation);
                GameObject placedObject = Instantiate(selectedObject, pose.position, pose.rotation);
                // SET COLOR
                

                string pts = placedObject.GetComponent<Z_color_Select>().GetPoints();
                
                 // SET GPS COORDINATES
                var loc = new Location()
                {
                    Latitude = Convert.ToDouble(this.latitude),
                    Longitude = Convert.ToDouble(this.longitude),
                    Altitude = 0.5f,
                    AltitudeMode = AltitudeMode.GroundRelative
                };

                var opts = new PlaceAtLocation.PlaceAtOptions()
                {
                    HideObjectUntilItIsPlaced = false,
                    MaxNumberOfLocationUpdates = 2,
                    MovementSmoothing = 0.1f,
                    UseMovingAverage = false
                };

                PlaceAtLocation.AddPlaceAtComponent(placedObject, loc, opts);

                //SEND THE OBJECT TO SERVER
                StartCoroutine(AddObjectServer(placedObject, pts));
            }

            

            //var anchorObject = new GameObject("PlacementAnchor");
            //anchorObject.transform.position = pose.position;
            //anchorObject.transform.rotation = pose.rotation;

            //placedObject.transform.parent = anchorObject.transform;

            //points.publicSendPointsToServer(selectedObject);
        }

    }

    private bool isDeleteVisible() 
    {
        GameObject parent = GameObject.Find("Canvas");

        Transform[] children =  parent.GetComponentsInChildren<Transform>(true);

        foreach(Transform ch in children)
        {
            if(ch.gameObject.name == "DeleteButton")
            {
                return ch.gameObject.activeInHierarchy;
            }
        }

        return false;
    }

    private bool isAnotherSelected()
    {
        GameObject found = GameObject.Find("AA_Selektah");
        if(found != null)
        {
            return true;
        }
        return false;
    }


    IEnumerator GetLocation()
    {
        
        Debug.Log("loc");
        // Check if the user has location service enabled.
        if (!Input.location.isEnabledByUser)
            yield break;
        Debug.Log("loc2");
        // Starts the location service.
        Input.location.Start(1);

        // Waits until the location service initializes
        int maxWait = 20;
        while (Input.location.status == LocationServiceStatus.Initializing && maxWait > 0)
        {
            yield return new WaitForSeconds(1);
            maxWait--;
        }
                Debug.Log("loc3");
        // If the service didn't initialize in 20 seconds this cancels location service use.
        if (maxWait < 1)
        {
            print("Timed out");
            yield break;
        }
                Debug.Log("loc4");
        // If the connection failed this cancels location service use.
        if (Input.location.status == LocationServiceStatus.Failed)
        {
            Debug.Log("Unable to determine device location");
            yield break;
        }
        else
        {
            // If the connection succeeded, this retrieves the device's current location and displays it in the Console window.
            //print("Location: " + Input.location.lastData.latitude + " " + Input.location.lastData.longitude + " " + Input.location.lastData.altitude + " " + Input.location.lastData.horizontalAccuracy + " " + Input.location.lastData.timestamp);
            Debug.Log(Input.location.lastData.longitude.ToString());
            this.longitude = Input.location.lastData.longitude.ToString();
            this.latitude = Input.location.lastData.latitude.ToString();
        }

        // Stops the location service if there is no need to query location updates continuously.
        Input.location.Stop();
    
    }

    public IEnumerator AddObjectServer(GameObject placedObj, string points)
    {
        string serverUrl = "https://smarthubs.media.tuwien.ac.at/api/add_object";

        WWWForm form = new WWWForm();
        
        
        if(points == null) {
            points = "4";
        }
        this.gameNumber = serverManager.GetComponent<CurrentGameConnect>().GetGameNumber();
        this.playerNumber = playerNumberObject.GetComponent<CurrentPlayerPicker>().GetPlayerNumber();
        
        placedObj.GetComponent<Z_color_Select>().SetObjectColor(playerNumber);

        form.AddField("game", this.gameNumber);
        form.AddField("player", this.playerNumber);
        form.AddField("points", points);
        form.AddField("oid", "1");
        if(selectedObject.name != null) {
            form.AddField("name", selectedObject.name);
        }
        form.AddField("longitude", this.longitude);
        form.AddField("latitude", this.latitude);

        using (UnityWebRequest www = UnityWebRequest.Post(serverUrl, form))
        {
            yield return www.SendWebRequest();

            if (www.result != UnityWebRequest.Result.Success)
            {
                //Debug.Log(www.error);
                // PROMPT ERROR
                //errorPanel.SetActive(true);
            }
            else
            {
                //Debug.Log("Form upload complete!");
                
            }
        }
    }

}