using System.Collections.Generic;
using System.Linq;
using UnityEngine;
using BaseGames.Core;
using BaseGames.Core.Events;
using BaseGames.Core.Save;
namespace BaseGames.World.Shop
{
///
/// 商店流程控制器(架构 15_MapShopModule §2.3)。
/// 管理库存可见性、购买逻辑、补货策略,并通过 ISaveable 持久化购买记录。
///
public class ShopController : MonoBehaviour, ISaveable
{
[SerializeField] private ShopInventorySO _inventory;
[SerializeField] private ShopPanel _shopPanel; // UI 面板(P4 UI 模块实现)
[Header("Event Channels(广播)")]
[SerializeField] private StringEventChannelSO _onShopOpen; // EVT_ShopOpened(shopId)
[SerializeField] private VoidEventChannelSO _onShopClosed; // EVT_ShopClosed
[SerializeField] private ShopPurchaseEventChannelSO _onItemPurchased; // EVT_ItemPurchased
[Header("Event Channels(订阅补货触发)")]
[SerializeField] private StringEventChannelSO _onBossDefeated; // EVT_BossDefeated
[SerializeField] private VoidEventChannelSO _onSavePointActivated; // EVT_SavePointActivated
// key = itemId,value = 已购次数
private Dictionary _purchaseCounts = new();
private HashSet _soldUniqueItems = new();
private List _availableItemsCache;
private bool _isDirty = true;
private readonly CompositeDisposable _subs = new();
private void OnEnable()
{
if (_inventory == null) return;
if (_inventory.RestockPolicy == RestockPolicy.OnBossDefeat)
_onBossDefeated?.Subscribe(OnBossDefeated).AddTo(_subs);
if (_inventory.RestockPolicy == RestockPolicy.OnSavePoint)
_onSavePointActivated?.Subscribe(OnSavePointActivated).AddTo(_subs);
ServiceLocator.GetOrDefault()?.Register(this);
}
private void OnDisable()
{
_subs.Clear();
ServiceLocator.GetOrDefault()?.Unregister(this);
}
private void OnBossDefeated(string _) => Restock();
private void OnSavePointActivated() => Restock();
// ── 公共 API ──────────────────────────────────────────────────────────
public void Open()
{
_shopPanel?.Show(GetAvailableItems(), this);
_onShopOpen?.Raise(_inventory.ShopId);
}
public void Close()
{
_shopPanel?.Hide();
_onShopClosed?.Raise();
}
/// 返回当前可购买的商品列表(过滤已售唯一品及超限商品)。结果在库存变更时才重建。
public List GetAvailableItems()
{
if (!_isDirty) return _availableItemsCache;
if (_inventory?.DefaultInventory == null)
{
_availableItemsCache = new List();
_isDirty = false;
return _availableItemsCache;
}
_availableItemsCache = _inventory.DefaultInventory
.Where(item => item != null
&& !_soldUniqueItems.Contains(item.ItemId)
&& (item.MaxPurchaseCount < 0 || GetPurchaseCount(item.ItemId) < item.MaxPurchaseCount))
.Take(_inventory.MaxDisplaySlots)
.ToList();
_isDirty = false;
return _availableItemsCache;
}
///
/// 按 RestockPolicy 补货:重置非唯一商品的购买次数(已售唯一品不恢复)。
///
public void Restock()
{
if (_inventory?.DefaultInventory == null) return;
var nonUniqueIds = _inventory.DefaultInventory
.Where(i => i != null && !i.IsUnique)
.Select(i => i.ItemId);
foreach (var id in nonUniqueIds)
_purchaseCounts.Remove(id);
_isDirty = true;
}
///
/// 尝试购买商品。由 ShopPanel 的购买按钮调用。
///
/// 购买成功返回 true;资金不足或商品不可购返回 false。
public bool TryPurchase(ShopItemSO item, int playerGeo)
{
if (item == null) return false;
int effectivePrice = GetEffectivePrice(item);
if (playerGeo < effectivePrice) return false;
if (_soldUniqueItems.Contains(item.ItemId)) return false;
if (item.MaxPurchaseCount >= 0 && GetPurchaseCount(item.ItemId) >= item.MaxPurchaseCount)
return false;
// 通过事件频道扣 Geo(PlayerStats 监听 EVT_ItemPurchased)
_onItemPurchased?.Raise(new ShopPurchaseEvent
{
ItemId = item.ItemId,
Price = effectivePrice,
});
// 更新库存状态
_purchaseCounts[item.ItemId] = GetPurchaseCount(item.ItemId) + 1;
if (item.IsUnique) _soldUniqueItems.Add(item.ItemId);
_isDirty = true;
return true;
}
///
/// 返回应用难度乘数后的实际价格。UI 层可通过此方法显示正确标价。
///
public int GetEffectivePrice(ShopItemSO item)
{
var scaler = ServiceLocator.GetOrDefault()?.CurrentScaler;
if (scaler == null) return item.BasePrice;
return Mathf.Max(1, Mathf.RoundToInt(item.BasePrice * scaler.ShopPriceMultiplier));
}
private int GetPurchaseCount(string id)
=> _purchaseCounts.TryGetValue(id, out var c) ? c : 0;
// ── ISaveable ─────────────────────────────────────────────────────────
public void OnSave(SaveData data)
{
if (_inventory == null) return;
if (!data.Shops.ShopRecords.ContainsKey(_inventory.ShopId))
data.Shops.ShopRecords[_inventory.ShopId] = new ShopRecord();
var record = data.Shops.ShopRecords[_inventory.ShopId];
record.SoldUniqueItems = _soldUniqueItems.ToList();
record.PurchaseCounts = new Dictionary(_purchaseCounts);
}
public void OnLoad(SaveData data)
{
if (_inventory == null) return;
if (data.Shops.ShopRecords.TryGetValue(_inventory.ShopId, out var record))
{
_soldUniqueItems = new HashSet(record.SoldUniqueItems ?? new List());
_purchaseCounts = record.PurchaseCounts ?? new Dictionary();
_isDirty = true;
}
}
}
// ─── ShopPanel ──────────────────────────────────────────────────────────
///
/// 商店 UI 面板基类。
/// ShopController 通过此接口调用面板显示/隐藏,已解耦具体 UI 实现。
///
public class ShopPanel : MonoBehaviour
{
public virtual void Show(List items, ShopController controller) { }
public virtual void Hide() { }
}
}