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

public class WorldCursor : MonoBehaviour
{
    private RaycastHit Hit;
    private Camera Cam;
    private ToolMode ActiveToolMode{get; set;}

    //Attributes for Highlighting of Facts when Mouse-Over
    private string selectableTag = "Selectable";
    private Transform lastFactSelection;

    //Attributes for simulating the drawing of a line
    public LineRenderer lineRenderer;
    private List<Vector3> linePositions = new List<Vector3>();
    private bool lineRendererActivated;

    void Start()
    {

        Cam = Camera.main;
        //Set MarkPointMode as the default ActiveToolMode
        this.ActiveToolMode = ToolMode.ExtraMode;//ToolMode.MarkPointMode;
        CommunicationEvents.ToolModeChangedEvent.Invoke(this.ActiveToolMode);
        //TODO: we probably can configure these things to automatically trigger when the variable is changed...
        CommunicationEvents.ActiveToolMode = this.ActiveToolMode;
        //redundant for now, but we probably want to have the activetool mode available globally
    }

    // Update is called once per frame
    void Update()
    {
        Ray ray = Cam.ScreenPointToRay(Input.mousePosition);

       
        int layerMask = 1 << LayerMask.NameToLayer("Player"); //only hit player
        layerMask = ~layerMask; //ignore Player

   

        if(Physics.Raycast(ray, out Hit, 30f, layerMask)){
            transform.position = Hit.point;
            transform.up = Hit.normal;
            transform.position += .01f * Hit.normal;

            //SELECTION-HIGHLIGHTING-PART
            //Check if a Fact was Hit
            Transform selection = Hit.transform;

            //Set the last Fact unselected
            if (this.lastFactSelection != null)
            {
                //Invoke the EndHighlightEvent that will be handled in FactSpawner
                CommunicationEvents.EndHighlightEvent.Invoke(this.lastFactSelection);
                this.lastFactSelection = null;
            }

            //Set the Fact that was Hit as selected
            if (selection.CompareTag(selectableTag))
            {
                //Invoke the HighlightEvent that will be handled in FactSpawner
                this.lastFactSelection = selection;
                CommunicationEvents.HighlightEvent.Invoke(selection);
            }
            //SELECTION-HIGHLIGHTING-PART-END

            CheckMouseButtons(ray);

            UpdateLineRenderer(transform.position);

        }
        else
        {
            transform.position = Cam.ScreenToWorldPoint(Input.mousePosition);
            transform.up = -Cam.transform.forward;
        }

        //Check if the ToolMode was switched
        CheckToolModeSelection();
        
    }

    //Deactivate LineRenderer so that no Line gets drawn when Cursor changes
    void DeactivateLineRenderer()
    {
        //Reset the first points
        this.lineRenderer.SetPosition(0, Vector3.zero);
        this.lineRenderer.SetPosition(1, Vector3.zero);
        if (linePositions.Count > 0)
            this.linePositions.Clear();
        this.lineRendererActivated = false;
    }

    //Check if left Mouse-Button was pressed and handle it
    void CheckMouseButtons(Ray ray)
    {
        if (Input.GetMouseButtonDown(0))
        {
            switch (this.ActiveToolMode)
            {
                case ToolMode.MarkPointMode:
                    //send HitEvent
                    CommunicationEvents.TriggerEvent.Invoke(Hit);
                    break;
                case ToolMode.ExtraMode:
                    //send HitEvent
                    CommunicationEvents.TriggerEvent.Invoke(Hit);
                    break;
                case ToolMode.DeleteMode:
                    //send HitEvent
                    CommunicationEvents.TriggerEvent.Invoke(Hit);
                    break;
                case ToolMode.CreateLineMode:
                    //Je nachdem ob erster oder der zweite Punkt angeklickt wurde behandeln

                    //Wenn erster Punkt einen Point-Collider erwischt hat:
                    //Linie aktivieren und Cursor folgen
                    //Wenn erster Punkt keinen Point-Collider erwischt hat:
                    //Nichts tun -> Evtl Hint einblenden

                    //Wenn zweiter Punkt einen Point-Collider erwischt hat:
                    //Event senden um GameObject-Line zu erzeugen
                    //Wenn zweiter Punkt keinen Point-Collider erwischt hat:
                    //Linie deaktivieren -> Evtl Hint einblenden

                    //LayerMask for Points
                    int layerMask = 1 << LayerMask.NameToLayer("Point"); //only hit Point

                    //Wenn bereits der erste Punkt markiert wurde
                    if (this.lineRendererActivated)
                    {
                        //If a second Point was Hit
                        if (Physics.Raycast(ray, out Hit, 30f, layerMask))
                        {
                            //Event for Creating the Line
                            Vector3 point1 = this.linePositions[0];
                            Vector3 point2 = Hit.transform.gameObject.transform.position;
                            this.DeactivateLineRenderer();
                            CommunicationEvents.AddLineEvent.Invoke(point1, point2);
                            break;
                        }
                        //If no Point was hit
                        else
                        {
                            //TODO: Hint that only a line can be drawn between already existing points
                            this.DeactivateLineRenderer();
                        }
                    }
                    //Wenn der erste Punkt noch nicht markiert wurde
                    else
                    {
                        //Check if a Point was hit
                        if (Physics.Raycast(ray, out Hit, 30f, layerMask))
                        {
                            //Set LineRenderer activated
                            this.lineRendererActivated = true;
                            //Add the position of the hit Point for the start of the Line
                            Vector3 temp = Hit.transform.gameObject.transform.position;
                            //temp += Vector3.up;

                            linePositions.Add(temp);
                            //The second point is the same point at the moment
                            linePositions.Add(temp);
                            this.lineRenderer.SetPosition(0, linePositions[0]);
                            this.lineRenderer.SetPosition(1, linePositions[1]);
                        }
                        else
                        {
                            //TODO: Hint that only a line can be drawn between already existing points
                        }
                    }

                    break;
            }
        }
    }

    //Updates the second-point of the Line when First Point was selected in LineMode
    void UpdateLineRenderer(Vector3 currentPosition)
    {
        if (this.ActiveToolMode == ToolMode.CreateLineMode)
        {
            if (this.lineRendererActivated)
            {
                this.linePositions[1] = currentPosition;
                this.lineRenderer.SetPosition(1, this.linePositions[1]);
            }
        }
    }

    void CheckToolModeSelection() {
        if (Input.GetButtonDown("ToolMode")) {
            //Change the ActiveToolMode dependent on which Mode was selected
            if ((int)this.ActiveToolMode == Enum.GetNames(typeof(ToolMode)).Length - 1)
            {
                this.ActiveToolMode = 0;
            }
            else {
                this.ActiveToolMode++;
            }
            CommunicationEvents.ActiveToolMode = this.ActiveToolMode;
            //Invoke the Handler for the Facts
            CommunicationEvents.ToolModeChangedEvent.Invoke(this.ActiveToolMode);
        }
    }

 

}