using System;
using System.Collections.Generic;
using System.Threading;
using UnityEngine;
using UnityEngine.UI;

namespace Cryville.Crtr.UI {
	public class Dialog : MonoBehaviour {
		static Dialog _instance;
		[SerializeField] CanvasGroup m_group;
		[SerializeField] Text m_msgText;
		[SerializeField] Text m_button0Text;
		[SerializeField] Text m_button1Text;
		[SerializeField] GameObject m_button1;
		[SerializeField] AnimationCurve m_fadeCurve;
		float _fadeDuration;
		static readonly Queue<DialogEntry> _queue = new Queue<DialogEntry>();
		struct DialogEntry {
			public Action<int> callback;
			public string message;
			public string action0;
			public string action1;
		}
		void Awake() {
			_instance = this;
			_fadeDuration = m_fadeCurve[m_fadeCurve.length - 1].time;
		}
		float _timer;
		DialogEntry? _cur;
		static bool _suppressed;
		void Update() {
			if (_cur == null) {
				if (_timer > 0) {
					_timer -= Time.deltaTime;
					if (_timer < 0) {
						_timer = 0;
						m_group.gameObject.SetActive(false);
					}
					m_group.alpha = m_fadeCurve.Evaluate(_timer);
				}
				if (_queue.Count > 0 && !_suppressed) {
					m_group.gameObject.SetActive(true);
					_cur = _queue.Dequeue();
					m_msgText.text = _cur.Value.message;
					m_button0Text.text = _cur.Value.action0;
					m_button1Text.text = _cur.Value.action1;
					m_button1.SetActive(_cur.Value.action1 != null);
				}
			}
			else {
				if (_timer < _fadeDuration) {
					_timer += Time.deltaTime;
					if (_timer > _fadeDuration) _timer = _fadeDuration;
					m_group.alpha = m_fadeCurve.Evaluate(_timer);
				}
			}
		}
		public void OnButton(int id) {
			if (_cur == null) return;
			var cb = _cur.Value.callback;
			if (cb != null) cb(id);
			_cur = null;
		}
		public static void Suppress() {
			_suppressed = true;
			if (_instance._cur != null) {
				_queue.Enqueue(_instance._cur.Value);
				_instance._cur = null;
			}
		}
		public static void Release() {
			_suppressed = false;
		}
		public static void Show(Action<int> callback, string message, string action0 = "OK", string action1 = null) {
			_queue.Enqueue(new DialogEntry { callback = callback, message = message, action0 = action0, action1 = action1 });
		}
		public static int ShowAndWait(string message, string action0 = "OK", string action1 = null) {
			using (var ev = new AutoResetEvent(false)) {
				int result = 0;
				_queue.Enqueue(new DialogEntry {
					callback = r => { result = r; ev.Set(); },
					message = message, action0 = action0, action1 = action1,
				});
				ev.WaitOne();
				return result;
			}
		}
	}
}
