using SVSim.BattleNode.Bridge;
using SVSim.BattleNode.Protocol;
namespace SVSim.BattleNode.Sessions;
///
/// One side of a battle. Two of these are held by a BattleSession; the session
/// brokers between them. Concrete impls (added in subsequent Phase-1 tasks):
///
/// - RealParticipant — WS-backed.
/// - NoOpBotParticipant — silent; for BattleType.Bot (AI-passive).
/// - ScriptedBotParticipant — wraps the v1.2 lifecycle for
/// BattleType.Scripted (solo testing harness).
///
///
public interface IBattleParticipant : IAsyncDisposable
{
/// Real viewer id, or a synthetic stable id for bots
/// ().
long ViewerId { get; }
/// Per-battle MatchContext snapshot, used for building Matched/BattleStart
/// selfInfo when this participant is "self" in the perspective.
MatchContext Context { get; }
/// Session calls this to deliver a frame from the OTHER participant
/// (or a server-synthesized broadcast). Real impl: encode + WS-send.
/// NoOp: swallow. Scripted: may emit a response via .
/// True for control frames (BattleFinish, JudgeResult, ack);
/// bypasses playSeq assignment + archive.
Task PushAsync(MsgEnvelope envelope, bool noStock, CancellationToken ct);
/// Participant fires this when it has a frame to send TO the session
/// (its own gameplay action). Real impl: fires on WS recv. NoOp: never fires.
/// Scripted: fires from inside PushAsync when the scripted lifecycle wants to
/// respond to an inbound frame.
event Func? FrameEmitted;
/// Drives the participant's inbound loop. For Real: the WS read loop
/// (returns when the WS closes). For NoOp/Scripted: completes immediately (the
/// session keeps running as long as the OTHER participant's RunAsync is alive).
Task RunAsync(CancellationToken ct);
/// Called when the battle ends. Concrete impls clean up (close WS, etc.).
Task TerminateAsync(BattleFinishReason reason);
}