using UnityEngine;
using UnityEngine.EventSystems;
using UnityEngine.UI;

namespace Cryville.Crtr.Config.UI {
	public abstract class PVPNumberBase : PropertyValuePanel {
		[SerializeField]
		EventTrigger m_ctn;
		[SerializeField]
		RectTransform m_handleArea;
		[SerializeField]
		Image m_handle;
		[SerializeField]
		Text m_text;
#pragma warning disable IDE0051
		protected void Start() {
			var ev = new EventTrigger.Entry { eventID = EventTriggerType.InitializePotentialDrag };
			ev.callback.AddListener(e => OnInitializePotentialDrag((PointerEventData)e));
			m_ctn.triggers.Add(ev);
			ev = new EventTrigger.Entry { eventID = EventTriggerType.Drag };
			ev.callback.AddListener(e => OnDrag((PointerEventData)e));
			m_ctn.triggers.Add(ev);
			ev = new EventTrigger.Entry { eventID = EventTriggerType.EndDrag };
			ev.callback.AddListener(e => OnEndDrag((PointerEventData)e));
			m_ctn.triggers.Add(ev);
			ev = new EventTrigger.Entry { eventID = EventTriggerType.PointerClick };
			ev.callback.AddListener(e => OnPointerClick((PointerEventData)e));
			m_ctn.triggers.Add(ev);
			OnIdle();
		}

		protected override void OnValueUpdated() {
			m_text.text = MappedValue.ToString();
		}

		protected virtual void OnIdle() { }

		void Update() {
			if (use) {
				SetRatio(GetRatioFromPos(pp));
				SetValueFromPos(pp);
			}
		}

		void OnRectTransformDimensionsChange() {
			m_handleArea.sizeDelta = new Vector2(m_handle.rectTransform.rect.height - m_handle.rectTransform.rect.width, 0);
		}
#pragma warning restore IDE0051

		Camera cam;
		Vector2 pp;
		bool use, nouse;
		public void OnInitializePotentialDrag(PointerEventData eventData) {
			eventData.useDragThreshold = false;
			pp = eventData.position;
		}

		public void OnDrag(PointerEventData eventData) {
			if (nouse) return;
			cam = eventData.pressEventCamera;
			if (!use) {
				var delta = eventData.position - pp;
				float dx = Mathf.Abs(delta.x), dy = Mathf.Abs(delta.y);
				if (dx > dy) use = true;
				else if (dx < dy) nouse = true;
			}
			if (use) {
				pp = eventData.position;
				eventData.Use();
			}
		}

		public void OnEndDrag(PointerEventData eventData) {
			if (!nouse) {
				SetValueFromPos(eventData.position);
				OnIdle();
				eventData.Use();
				use = false;
			}
			nouse = false;
		}

		public void OnPointerClick(PointerEventData eventData) {
			SetValueFromPos(eventData.position);
			eventData.Use();
		}

		float GetRatioFromPos(Vector2 pos) {
			Vector2 lp;
			if (RectTransformUtility.ScreenPointToLocalPointInRectangle(m_handleArea, pos, cam, out lp)) {
				lp -= m_handleArea.rect.position;
				return Mathf.Clamp01(lp.x / m_handleArea.rect.width);
			}
			return float.NegativeInfinity;
		}

		void SetValueFromPos(Vector2 pos) {
			double min = double.NegativeInfinity, max = double.PositiveInfinity;
			if (Range != null && Range.Length == 2) {
				min = (double)Range[0];
				max = (double)Range[1];
			}
			double ratio = GetRatioFromPos(pos);
			double result = GetValue(ratio, Time.deltaTime, min, max);
			if (result < min) result = min;
			else if (result > max) result = max;
			RawValue = result;
		}

		protected abstract double GetValue(double ratio, float deltaTime, double min, double max);

		protected void SetRatio(float ratio) {
			m_handle.rectTransform.anchorMin = new Vector2(ratio, m_handle.rectTransform.anchorMin.y);
			m_handle.rectTransform.anchorMax = new Vector2(ratio, m_handle.rectTransform.anchorMax.y);
			m_handle.rectTransform.anchoredPosition = Vector2.zero;
		}
	}
}
