using System;
using System.Collections;
using System.Collections.Generic;
using UnityEngine;

namespace SC.XR.Unity.Module_Tooltip
{
    [ExecuteAlways]
    [RequireComponent(typeof(LineRenderer))]
    public class Modules_TooltipLineRenderer : MonoBehaviour
    {
        public enum TooltipStartPointLocation
        {
            Auto,
            UpperLeft,
            UpperCenter,
            UpperRight,
            MiddleLeft,
            MiddleCenter,
            MiddleRight,
            BottomLeft,
            BottomCenter,
            BottonRight
        }
        [SerializeField]
        [Tooltip("Select the starting point of the line.")]
        private TooltipStartPointLocation tooltipStartPointLocation = TooltipStartPointLocation.Auto;
        [SerializeField]
        [Tooltip("The GameObject which the tooltip is connected to.")]
        private Transform target;
        [SerializeField]
        [Tooltip("Whether the point is visible.")]
        private bool isStartPointVisible;
        [SerializeField]
        [Tooltip("Whether the line is visible.")]
        private bool isLineVisible;
        private Transform Target
        {
            set { target = value; }
            get { return target; }
        }

        [SerializeField]
        [Range(0, 0.01f)]
        [Tooltip("The width of line")]
        private float width;

        private float Width
        {
            set { width = value; }
            get { return width; }
        }

        private LineRenderer lineRenderer;
        private Transform lable;
        private Transform background;
        private Transform[] startpoints;
        private Transform startpoint;
        private Dictionary<float, Transform> distanceDictionary;
        private List<float> distanceList;
        private Transform point;

        private void OnEnable()
        {
            lineRenderer = GetComponent<LineRenderer>();
            lable = transform.Find("Lable");
            background = lable.Find("Background");
            lineRenderer.useWorldSpace = false;
            startpoints = background.GetComponentsInChildren<Transform>();
            point = transform.Find("Point");
        }

        protected virtual void Update()
        {
            //Target = target;
            lineRenderer.widthMultiplier = Width;
            UpdateLine();
            SetVisible();
        }
        private void UpdateLine()
        {
            Vector3 point_start = GetStartPoint();
            Vector3[] points = { transform.InverseTransformPoint(point_start), transform.InverseTransformPoint(Target.position) };
            lineRenderer.SetPositions(points);
        }

        private Vector3 GetStartPoint()
        {
            switch (tooltipStartPointLocation)
            {
                case TooltipStartPointLocation.Auto:
                    startpoint = GetNearbyPoint(startpoint);
                    break;
                case TooltipStartPointLocation.UpperLeft:
                    startpoint = startpoints[1];
                    break;
                case TooltipStartPointLocation.UpperCenter:
                    startpoint = startpoints[2];
                    break;
                case TooltipStartPointLocation.UpperRight:
                    startpoint = startpoints[3];
                    break;
                case TooltipStartPointLocation.MiddleLeft:
                    startpoint = startpoints[4];
                    break;
                case TooltipStartPointLocation.MiddleCenter:
                    startpoint = startpoints[5];
                    break;
                case TooltipStartPointLocation.MiddleRight:
                    startpoint = startpoints[6];
                    break;
                case TooltipStartPointLocation.BottomLeft:
                    startpoint = startpoints[7];
                    break;
                case TooltipStartPointLocation.BottomCenter:
                    startpoint = startpoints[8];
                    break;
                case TooltipStartPointLocation.BottonRight:
                    startpoint = startpoints[9];
                    break;
                default:
                    break;
            }
            return startpoint.position;
        }
        private Transform GetNearbyPoint(Transform startpoint)
        {
            distanceDictionary = new Dictionary<float, Transform>();
            distanceList = new List<float>();
            for (int i = 0; i < 9; i++)
            {
                float distance = Vector3.Distance(Target.position, startpoints[i + 1].position);
                try
                {
                    distanceDictionary.Add(distance, startpoints[i + 1]);
                }
                catch (Exception)
                {

                }
                if (!distanceList.Contains(distance))
                {
                    distanceList.Add(distance);
                }
            }
            distanceList.Sort();
            distanceDictionary.TryGetValue(distanceList[0], out startpoint);
            return startpoint;
        }
        private void SetVisible()
        {
            point.gameObject.GetComponent<MeshRenderer>().enabled = isStartPointVisible;
            lineRenderer.enabled = isLineVisible;
        }
        public Vector3 API_GetTargetPosition(bool isWorld)
        {
            if (isWorld)
            {
                return Target.position;
            }
            else
            {
                return transform.InverseTransformPoint(Target.position);
            }
        }
        public void API_SetTargetPosition(Vector3 newPosition, bool isWorld)
        {
            if (isWorld)
            {
                Target.transform.position = newPosition;
            }
            else
            {
                Target.transform.position = transform.TransformPoint(newPosition);
            }
        }
        public Vector3 API_GetLablePosition(bool isWorld)
        {
            if (lable == null)
            {
                lable = transform.Find("Lable");
            }
            if (isWorld)
            {
                return lable.transform.position;
            }
            else
            {
                return transform.InverseTransformPoint(lable.position);
            }
        }
        public void API_SetLablePosition(Vector3 newPosition, bool isWorld)
        {
            if (lable == null)
            {
                lable = transform.Find("Lable");
            }
            if (isWorld)
            {
                lable.transform.position = newPosition;
            }
            else
            {
                lable.transform.position = transform.TransformPoint(newPosition);
            }
        }
        public TooltipStartPointLocation API_GetStartPoint()
        {
            return tooltipStartPointLocation;
        }
        public void API_SetStartPoint(TooltipStartPointLocation startPoint)
        {
            tooltipStartPointLocation = startPoint;
        }
        public Vector3 API_GetStartPointPosition(bool isWorld)
        {
            if (isWorld)
            {
                return startpoint.position;
            }
            else
            {
                return transform.InverseTransformPoint(startpoint.position);
            }
        }
        public void API_SetStartPointVisible(bool state)
        {
            isStartPointVisible = state;
        }
        public void API_SetLineVisible(bool state)
        {
            isLineVisible = state;
        }
        public void API_SetLineWidth(float width)
        {
            Width = width;
        }
    }
}