using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using UnityEngine.EventSystems;
using TMPro;
using BaseGames.Core;
using BaseGames.Core.Events;
using BaseGames.Localization;
namespace BaseGames.UI
{
///
/// 图鉴面板(数据驱动,仿 )。据 列出全部敌人,
/// 经 (ServiceLocator) 读已发现态:已发现亮显,未发现 "???"+剪影+锁。
/// 订阅 EVT_BestiaryUpdated 实时刷新;点击格子在右侧详情区展示名/描述/数值/击杀数;显示完成度 X/Y。
/// 菜单态(无游戏,service=null)下全部显示未发现。
///
public class BestiaryPanel : MonoBehaviour, IFocusable
{
[Header("数据 / 单元格")]
[SerializeField] private BestiaryDatabaseSO _database;
[Tooltip("敌人格的父节点(通常挂 GridLayoutGroup)。")]
[SerializeField] private Transform _container;
[SerializeField] private BestiaryCellView _cellPrefab;
[Header("头部 / 关闭")]
[Tooltip("完成度文本(X / Y)。")]
[SerializeField] private TMP_Text _completionText;
[SerializeField] private Button _btnClose;
[Header("详情区")]
[SerializeField] private Image _detailIcon;
[SerializeField] private LocalizedText _detailName;
[SerializeField] private TMP_Text _detailDesc;
[SerializeField] private TMP_Text _detailStats;
[Header("Event Channels")]
[Tooltip("图鉴更新广播(payload=enemyId),用于实时刷新。对应 EVT_BestiaryUpdated。")]
[SerializeField] private StringEventChannelSO _onBestiaryUpdated;
private readonly List<(BestiaryCellView view, BestiaryDatabaseSO.Entry entry)> _cells = new();
private readonly CompositeDisposable _subs = new();
private IBestiaryService _service;
private void Awake() => _btnClose?.onClick.AddListener(OnClose);
private void OnEnable()
{
_onBestiaryUpdated?.Subscribe(_ => RefreshStates()).AddTo(_subs);
_service = ServiceLocator.GetOrDefault(); // 菜单态为 null → 全部未发现
BuildList();
ShowDetail(-1);
}
private void OnDisable() => _subs.Clear();
// ── 列表构建 ──────────────────────────────────────────────────────────
public void BuildList()
{
ClearList();
if (_database == null || _container == null || _cellPrefab == null) return;
var entries = _database.Entries;
if (entries == null) return;
for (int i = 0; i < entries.Length; i++)
{
var entry = entries[i];
var cell = Instantiate(_cellPrefab, _container);
cell.gameObject.SetActive(true);
cell.Bind(entry.displayNameKey, entry.icon, IsDiscovered(entry));
int idx = i;
if (cell.SelectButton != null)
cell.SelectButton.onClick.AddListener(() => ShowDetail(idx));
_cells.Add((cell, entry));
}
UpdateCompletion();
}
private void RefreshStates()
{
if (_service == null) _service = ServiceLocator.GetOrDefault();
foreach (var (view, entry) in _cells)
if (view != null) view.SetDiscovered(IsDiscovered(entry));
UpdateCompletion();
}
private bool IsDiscovered(BestiaryDatabaseSO.Entry entry)
=> _service != null && _service.IsDiscovered(entry.enemyId);
private void UpdateCompletion()
{
if (_completionText == null) return;
int total = _database != null && _database.Entries != null ? _database.Entries.Length : 0;
int found = 0;
foreach (var (_, entry) in _cells) if (IsDiscovered(entry)) found++;
_completionText.text = $"{found} / {total}";
}
// ── 详情 ──────────────────────────────────────────────────────────────
private void ShowDetail(int index)
{
bool valid = index >= 0 && index < _cells.Count;
var entry = valid ? _cells[index].entry : default;
bool discovered = valid && IsDiscovered(entry);
if (_detailIcon != null)
{
_detailIcon.sprite = discovered ? entry.icon : null;
_detailIcon.enabled = discovered && entry.icon != null;
}
if (_detailName != null)
_detailName.SetKey(!valid ? "" : (discovered ? entry.displayNameKey : "BESTIARY_LOCKED"));
if (_detailDesc != null)
{
if (!valid) _detailDesc.text = "";
else if (!discovered) _detailDesc.text = LocalizationManager.Get("BESTIARY_LOCKED_DESC", LocalizationTable.UI);
else
{
string d = LocalizationManager.Get(entry.descKey, LocalizationTable.UI);
_detailDesc.text = string.IsNullOrEmpty(d) || d == entry.descKey ? "" : d;
}
}
if (_detailStats != null)
{
if (!valid || !discovered) { _detailStats.text = ""; }
else
{
int kills = _service != null ? _service.GetKillCount(entry.enemyId) : 0;
string hpLabel = LocalizationManager.Get("BESTIARY_HP", LocalizationTable.UI);
string killLabel = LocalizationManager.Get("BESTIARY_KILLS", LocalizationTable.UI);
var sb = new System.Text.StringBuilder();
if (entry.displayMaxHP > 0) sb.Append(hpLabel).Append(' ').Append(entry.displayMaxHP).Append(" ");
sb.Append(killLabel).Append(' ').Append(kills);
_detailStats.text = sb.ToString();
}
}
}
private void ClearList()
{
_cells.Clear();
if (_container == null) return;
for (int i = _container.childCount - 1; i >= 0; i--)
{
var c = _container.GetChild(i).gameObject;
if (Application.isPlaying) Destroy(c); else DestroyImmediate(c);
}
}
private void OnClose()
{
var uiMgr = ServiceLocator.GetOrDefault();
if (uiMgr != null) uiMgr.CloseTopPanel();
else gameObject.SetActive(false);
}
// ── IFocusable ────────────────────────────────────────────────────────
public void OnFocusRestored()
{
GameObject target = _cells.Count > 0 && _cells[0].view != null && _cells[0].view.SelectButton != null
? _cells[0].view.SelectButton.gameObject
: _btnClose != null ? _btnClose.gameObject : null;
if (target != null) EventSystem.current?.SetSelectedGameObject(target);
}
}
}