using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.XR;
using UnityEngine.XR.Interaction.Toolkit;
using PDollarGestureRecognizer;
using System.IO;
using UnityEngine.Events;

public class GestureRecognizer : MonoBehaviour
{
    //public InputDevice rightHandController;
    public XRNode rightHandSource;
    public InputHelpers.Button rightInputButton;
    public InputHelpers.Button rightControlButton;

    public float inputThreshold = 0.1f;
    public Transform movementSource;

    public float newPositionThresholdDistance = 0.05f;
    public GameObject debugCubePrefab;
    public bool creationMode = true;
    public string newGestureName;

    public float recognitionThreshold = 0.8f;

    [System.Serializable]
    public class UnityStringEvent : UnityEvent<string> { }
    public UnityStringEvent OnRecognized;

    private List<Gesture> trainingSet = new List<Gesture>();
    private bool isMoving = false;
    private List<Vector3> positionsList = new List<Vector3>();

    // Start is called before the first frame update
    void Start()
    {
        // Path = ..\AppData\LocalLow\DefaultCompany\Heroes of Hiis SCM
        Debug.Log(Application.persistentDataPath);
        string[] gestureFiles = Directory.GetFiles(Application.persistentDataPath, "*.xml");
        foreach (var item in gestureFiles)
        {
            trainingSet.Add(GestureIO.ReadGestureFromFile(item));
        }
        foreach (var item in trainingSet)
        {
            Debug.Log(item.Name);
        }
    }

    // Update is called once per frame
    void Update()
    {
        InputHelpers.IsPressed(InputDevices.GetDeviceAtXRNode(rightHandSource), rightInputButton, out bool isPressed, inputThreshold);
        InputHelpers.IsPressed(InputDevices.GetDeviceAtXRNode(rightHandSource), rightControlButton, out bool isControlPressed, inputThreshold);

        bool startGesture = isPressed && isControlPressed;

        // Start the movement
        if (!isMoving && startGesture)
        {
            StartMovement();
            //StartCoroutine("Haptics");
        }
        // Ending the movement
        else if (isMoving && !startGesture)
        {
            EndMovement();
            //StopCoroutine("Haptics");
        }
        // Updating the movement
        else if (isMoving && startGesture)
        {
            UpdateMovement();
        }
    }
    // Still needs to be tested
    //IEnumerator Haptics() 
    //{
     //   while (true)
      //  {
         //   rightHandController.SendHapticImpulse(0u, 0.7f, 0.2f);
       // }
    //}

    void StartMovement()
    {
        Debug.Log("Movement started");
        isMoving = true;
        positionsList.Clear();
        positionsList.Add(movementSource.position);
        if (debugCubePrefab)
        {
            Destroy(Instantiate(debugCubePrefab, movementSource.position, Quaternion.identity), 3);
        }
    }
    void EndMovement()
    {
        Debug.Log("Movement ended");
        isMoving = false;

        // Create gesture from position list
        Point[] pointArray = new Point[positionsList.Count];
        for (int i = 0; i < positionsList.Count; i++)
        {
            Vector2 screenPoint = Camera.main.WorldToScreenPoint(positionsList[i]);
            pointArray[i] = new Point(screenPoint.x, screenPoint.y, 0);
        }

        Gesture newGesture = new Gesture(pointArray);

        // Add gesture to training set. (only for demo)
        if (creationMode)
        {
            newGesture.Name = newGestureName;
            trainingSet.Add(newGesture);

            string fileName = Application.persistentDataPath + "/" + newGestureName + ".xml";
            GestureIO.WriteGesture(pointArray, newGestureName, fileName);
        }
        // Recognize
        else
        {
            Result result = PointCloudRecognizer.Classify(newGesture, trainingSet.ToArray());

            if (result.Score > recognitionThreshold)
            {
                OnRecognized.Invoke(result.GestureClass);
                
            }
        }
    }

    void UpdateMovement()
    {
        Vector3 lastPosition = positionsList[positionsList.Count - 1];
        if (Vector3.Distance(movementSource.position, lastPosition) > newPositionThresholdDistance)
        {
            positionsList.Add(movementSource.position);
            if (debugCubePrefab)
            {
                Destroy(Instantiate(debugCubePrefab, movementSource.position, Quaternion.identity), 3);
            }
        }
    }
}