using System;
using System.Collections;
using TMPro;
using UnityEngine;
using UnityEngine.Events;
using CG.Utils;

namespace CG.Speech
{
    public class SpeechInputAdapter : MonoBehaviour
    {
        [Header("UI")]
        public TMP_Text partialText;
        public TMP_Text finalText;

        [Header("Traditional Chinese (OpenCC)")]
        [Tooltip("opencc.exe 的完整路徑；先空著也能跑（就不轉繁）")]
        public string openccExePath = "";
        [Tooltip("OpenCC config：常用 s2twp.json（台灣用字）或 s2tw.json")]
        public string openccConfig = "s2twp.json";
        [Tooltip("partial 也要轉繁（較吃性能）。建議打勾但會節流。")]
        public bool convertPartial = true;

        [Header("Partial throttling")]
        [Tooltip("partial 轉繁更新最短間隔（秒），避免每幀呼叫 OpenCC）")]
        public float partialUpdateInterval = 0.15f;

        [Header("Events")]
        public UnityEvent<string> onUtteranceFinal;   // 已轉繁的 final
        public UnityEvent onPauseListening;           // 送出後暫停聽（你可綁 Recognissimo Stop）
        public UnityEvent onResumeListening;          // 回覆完後恢復聽（你可綁 Recognissimo Start）
        public UnityEvent onCancelCurrent;            // 取消本輪（Router 會用）

        private ITextNormalizer _normalizer;
        private string _latestPartialRaw = "";
        private float _nextPartialTime;
        private Coroutine _partialLoop;

        private void Awake()
        {
            _normalizer = BuildNormalizer();
        }

        private void OnEnable()
        {
            _partialLoop ??= StartCoroutine(PartialLoop());
        }

        private void OnDisable()
        {
            if (_partialLoop != null)
            {
                StopCoroutine(_partialLoop);
                _partialLoop = null;
            }
        }

        private ITextNormalizer BuildNormalizer()
        {
            if (string.IsNullOrWhiteSpace(openccExePath))
                return new PassthroughNormalizer();

            return new OpenCCExternalProcessNormalizer(openccExePath, openccConfig);
        }

        // ==== Bind these from Recognissimo ====

        // Recognissimo partial callback (raw, usually Simplified)
        public void OnAsrPartialRaw(string raw)
        {
            raw ??= "";
            _latestPartialRaw = raw;

            if (!convertPartial && partialText != null)
                partialText.text = raw;
        }

        // Recognissimo final callback (raw)
        public void OnAsrFinalRaw(string raw)
        {
            raw ??= "";
            var zhTW = _normalizer.Normalize(raw);

            // UI: final history (simple)
            if (finalText != null)
                finalText.text = zhTW;

            if (partialText != null)
                partialText.text = ""; // clear partial

            // Pause listening (default strategy)
            onPauseListening?.Invoke();

            // Fire event for router/chat
            onUtteranceFinal?.Invoke(zhTW);
        }

        // Called by ChatOrchestrator when reply done
        public void ResumeListening()
        {
            onResumeListening?.Invoke();
        }

        public void CancelCurrent()
        {
            onCancelCurrent?.Invoke();
        }

        private IEnumerator PartialLoop()
        {
            while (true)
            {
                if (convertPartial && Time.time >= _nextPartialTime)
                {
                    _nextPartialTime = Time.time + Mathf.Max(0.05f, partialUpdateInterval);

                    if (partialText != null)
                    {
                        var raw = _latestPartialRaw ?? "";
                        var zhTW = _normalizer.Normalize(raw);
                        partialText.text = zhTW;
                    }
                }
                yield return null;
            }
        }
    }
}
