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

// 화자 몸통 앞에 떠 있는 World-space 선택지 UI 싱글턴
// DialogPlayer가 Show()를 await해서 선택된 인덱스를 받아감
public class ChoiceHud : MonoBehaviour
{
    public static ChoiceHud Instance { get; private set; }

    [Header("Refs")]
    [SerializeField] private GameObject _root;
    [SerializeField] private Transform _rowContainer;
    [SerializeField] private DialogChoiceRow _rowPrefab;
    [SerializeField] private TMP_Text ChoiceQuestion;

    [Header("Placement")]
    [SerializeField] private float _chestHeight = 1.2f;    // 화자 발 기준 가슴 높이
    [SerializeField] private float _forwardOffset = 0.5f;  // 화자→플레이어 방향으로 띄울 거리

    private Transform _speakerTransform;
    private readonly List<DialogChoiceRow> _rows = new();
    private AwaitableCompletionSource<int> _completion;

    private void Awake()
    {
        if (Instance != null && Instance != this) { Destroy(gameObject); return; }
        Instance = this;
        if (_root == null) _root = gameObject;
        Hide();
    }

    private void OnDestroy()
    {
        if (Instance == this) Instance = null;
    }

    private void OnDisable()
    {
        // 진행 중 대기 정리 (씬 전환 등으로 비활성화될 때)
        _completion?.TrySetCanceled();
        _completion = null;
    }

    public async Awaitable<int> Show(CharacterData speaker,string choiceQuestion, List<DialogChoice> choices)
    {
        if (choices == null || choices.Count == 0) return 0;

        _speakerTransform = speaker != null ? CharacterVoiceObject.Find(speaker)?.transform : null;

        ChoiceQuestion.text = choiceQuestion;
        ClearRows();
        for (int i = 0; i < choices.Count; i++)
        {
            var row = Instantiate(_rowPrefab, _rowContainer);
            row.Bind(i, choices[i].ChoiceText);
            row.OnClicked += HandleClicked;
            _rows.Add(row);
        }

        _root.SetActive(true);
        _completion = new AwaitableCompletionSource<int>();

        int result;
        try
        {
            result = await _completion.Awaitable;
        }
        finally
        {
            _completion = null;
            Hide();
        }
        return result;
    }

    private void HandleClicked(int index)
    {
        _completion?.TrySetResult(index);
    }

    private void Hide()
    {
        ChoiceQuestion.text = "";
        ClearRows();
        if (_root != null) _root.SetActive(false);
        _speakerTransform = null;
    }

    private void ClearRows()
    {
        foreach (var row in _rows)
        {
            if (row == null) continue;
            row.OnClicked -= HandleClicked;
            Destroy(row.gameObject);
        }
        _rows.Clear();
    }

    private void LateUpdate()
    {
        if (_root == null || !_root.activeSelf) return;
        if (_speakerTransform == null || Camera.main == null) return;

        var camTr = Camera.main.transform;

        // 화자에서 플레이어 카메라로 향하는 수평 방향 (yaw만)
        Vector3 toCam = camTr.position - _speakerTransform.position;
        toCam.y = 0f;
        if (toCam.sqrMagnitude < 0.0001f) return;
        Vector3 dir = toCam.normalized;

        Vector3 chestWorld = _speakerTransform.position + Vector3.up * _chestHeight;
        _root.transform.position = chestWorld + dir * _forwardOffset;

        // 빌보드 — 캔버스의 -Z(읽는 면)가 카메라를 향하도록 +Z를 카메라 반대로
        _root.transform.rotation = Quaternion.LookRotation(-dir);
    }
}
