using SVSim.BattleNode.Bridge;
namespace SVSim.EmulatedEntrypoint.Matching;
///
/// Phase 3 hardcoded fixture: one stub bot per class (1..8). ai_id values are
/// the "series 1" tier from the client's rm_ai_setting.csv master table
/// (1111=Forest, 1121=Sword, … 1181=Portal). The client's
/// RankMatchAISettingList.GetSettingData(aiId) calls .First(...) against
/// this table and throws InvalidOperationException if the id is absent — so the
/// ids MUST match. See data_dumps/client-assets/rm_ai_setting.csv for the full
/// catalog (32 rows: classes 1-8 × tiers 1-2 × deck variants 1-2).
///
public sealed class BotRoster : IBotRoster
{
// Cosmetic ids (sleeve / emblem / degree / field) intentionally use safe
// default values that match the master tables shipped in the project.
// The client-side AI catalog reads ai_id but renders cosmetics from the
// sleeveId/emblemId/etc returned here.
private static readonly IReadOnlyList Roster = new[]
{
new AIBotProfile(AiId: 1111, CountryCode: "NONE", UserName: "Forestcraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 1, CharaId: 1, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
new AIBotProfile(AiId: 1121, CountryCode: "NONE", UserName: "Swordcraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 2, CharaId: 2, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
new AIBotProfile(AiId: 1131, CountryCode: "NONE", UserName: "Runecraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 3, CharaId: 3, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
new AIBotProfile(AiId: 1141, CountryCode: "NONE", UserName: "Dragoncraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 4, CharaId: 4, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
new AIBotProfile(AiId: 1151, CountryCode: "NONE", UserName: "Shadowcraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 5, CharaId: 5, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
new AIBotProfile(AiId: 1161, CountryCode: "NONE", UserName: "Bloodcraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 6, CharaId: 6, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
new AIBotProfile(AiId: 1171, CountryCode: "NONE", UserName: "Havencraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 7, CharaId: 7, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
new AIBotProfile(AiId: 1181, CountryCode: "NONE", UserName: "Portalcraft AI",
SleeveId: 1001, EmblemId: 1, DegreeId: 1, FieldId: 1, IsOfficial: 0,
ClassId: 8, CharaId: 8, Rank: 10, BattlePoint: 0, IsMasterRank: 0, MasterPoint: 0),
};
public AIBotProfile Pick(MatchContext selfCtx)
{
// Deterministic: hash the ctx and pick from the roster. Same ctx →
// same bot so a mid-flight retry of /ai_/start returns the same
// opponent (no fresh roster pick on each call).
var hash = StringComparer.Ordinal.GetHashCode(selfCtx.UserName)
^ StringComparer.Ordinal.GetHashCode(selfCtx.ClassId);
var index = (int)((uint)hash % Roster.Count);
return Roster[index];
}
}