using System.Collections;
using System.Collections.Generic;
using System.Text;
using TMPro;
using UnityEngine;
using UnityEngine.UI;
using BaseGames.Localization;
namespace BaseGames.Dialogue
{
///
/// 对话框 UI 组件(架构 14_NarrativeModule §5)。
/// 挂载在 Canvas_Overlay 下的 DialogueBox 子对象。
/// 负责打字机效果、头像显示、继续提示。
///
public class DialogueUI : MonoBehaviour
{
[SerializeField] private GameObject _rootPanel;
[SerializeField] private TMP_Text _speakerNameText;
[SerializeField] private TMP_Text _dialogueText;
[SerializeField] private GameObject _speakerNamePanel; // 无名称时隐藏整个名称框
[SerializeField] private GameObject _continuePrompt; // "▼" 图标,打字完成后显示
[SerializeField] private Image _speakerPortrait; // 角色头像框
[SerializeField] private Image _speakerNameBackground; // 说话人名称框背景,用于应用 accentColor(可选)
[SerializeField] private AudioSource _voiceSource; // 语音播放源(可不配置)
[Header("选项系统(可选)")]
[Tooltip("选项按钮的父节点容器。ShowChoices 通过对象池激活/停用按钮,HideChoices 停用全部。\n留空则分支选项功能静默禁用。")]
[SerializeField] private Transform _choicesContainer;
[Tooltip("选项按钮预制体(需包含 Button 组件和 TMP_Text 子组件)。\n首次使用时预热 PoolInitialSize 个到对象池,后续零 GC。")]
[SerializeField] private GameObject _choiceButtonPrefab;
[Tooltip("选项按钮池初始大小。设为预期最大选项数,默认 8 覆盖绝大多数情况。")]
[SerializeField] [Range(2, 16)] private int _choicePoolSize = 8;
// 说话人名称框背景的默认色(Awake 时记录,切换角色后可还原)
private Color _defaultNameBgColor = Color.white;
// 缓存名称框 RectTransform,避免 ShowLine 每次调用 GetComponent(零堆分配)
private RectTransform _speakerNamePanelRT;
// 选项按钮对象池:Awake 时按 _choicePoolSize 预热,ShowChoices/HideChoices 零 GC
private readonly List<(GameObject go, Button btn, TMP_Text lbl)> _choicePool = new();
private Coroutine _typingCoroutine;
private DialogueLine _currentLine;
private const float DefaultTypewriterDelay = 0.03f;
// 缓存 WaitForSecondsRealtime:delay 值不变时直接复用,避免每行 new 分配。
private WaitForSecondsRealtime _cachedTypeDelay;
private float _cachedTypeDelayValue = -1f;
// 缓存 StringBuilder:每行 Clear() 复用,避免每行 new StringBuilder(n) 的堆分配。
// 初始容量 256,足以容纳绝大多数对话行,超长时会自动扩容(扩容极少发生)。
private readonly StringBuilder _typingSB = new(256);
/// 当前是否仍在执行打字机效果。
public bool IsTyping { get; private set; }
private void Awake()
{
if (_speakerNameBackground != null)
_defaultNameBgColor = _speakerNameBackground.color;
if (_speakerNamePanel != null)
_speakerNamePanelRT = _speakerNamePanel.GetComponent();
// 预热选项按钮对象池:在此时创建可避免首次对话时的 Instantiate 停顿
if (_choicesContainer != null && _choiceButtonPrefab != null)
{
for (int i = 0; i < _choicePoolSize; i++)
{
var go = Instantiate(_choiceButtonPrefab, _choicesContainer);
var btn = go.GetComponent