using SVSim.BattleNode.Protocol.Bodies;
namespace SVSim.BattleNode.Sessions.Dispatch;
/// Pure transforms from the active player's RawBody sub-structures to the opponent-facing
/// shapes. No session state, no wire I/O — unit-testable in isolation. RawBody nested values arrive
/// as Dictionary<string,object?> / List<object?> with numeric leaves boxed
/// as long/int/double (see MsgEnvelope.FromJson).
internal static class KnownListBuilder
{
/// The played card's knownList entry, or null when its identity can't be synthesized
/// (token idx not in the deck map, or no matching move op). spellboost/attachTarget default to
/// 0/"" for the vanilla slice; cost/clan/tribe are deferred (receiver re-derives from cardId).
public static KnownCardEntry? BuildPlayedCard(
IReadOnlyDictionary deckMap, int playIdx, object? orderList)
{
if (!deckMap.TryGetValue(playIdx, out var cardId)) return null;
var to = ExtractMoveTo(orderList, playIdx);
if (to is null) return null;
return new KnownCardEntry(Idx: playIdx, CardId: cardId, To: to.Value, Spellboost: 0, AttachTarget: "");
}
/// The to place-state of the FIRST move op whose idx list contains
/// (the played card's own move; later add/alter ops are the deferred
/// token slice), or null if absent. NOTE: the sender-side to is passed through verbatim —
/// for the vanilla slice we assume send-side and recv-side place-state codes match, pending
/// recv-capture confirmation.
public static int? ExtractMoveTo(object? orderList, int playIdx)
{
if (orderList is not IEnumerable