using MessagePack; using System.Text.Json.Serialization; namespace SVSim.EmulatedEntrypoint.Models.Dtos; [MessagePackObject] public class PackConfigDto { [JsonPropertyName("parent_gacha_id")] [Key("parent_gacha_id")] public int ParentGachaId { get; set; } [JsonPropertyName("base_pack_id")] [Key("base_pack_id")] public int BasePackId { get; set; } [JsonPropertyName("override_draw_effect_pack_id")] [Key("override_draw_effect_pack_id")] public int OverrideDrawEffectPackId { get; set; } [JsonPropertyName("override_ui_effect_pack_id")] [Key("override_ui_effect_pack_id")] public int OverrideUiEffectPackId { get; set; } [JsonPropertyName("gacha_type")] [Key("gacha_type")] public int GachaType { get; set; } [JsonPropertyName("sleeve_id")] [Key("sleeve_id")] public int SleeveId { get; set; } = 3000011; [JsonPropertyName("special_sleeve_id")] [Key("special_sleeve_id")] public int SpecialSleeveId { get; set; } [JsonPropertyName("commence_date")] [Key("commence_date")] public string CommenceDate { get; set; } = string.Empty; [JsonPropertyName("complete_date")] [Key("complete_date")] public string CompleteDate { get; set; } = string.Empty; [JsonPropertyName("cardpack_banner_list")] [Key("cardpack_banner_list")] public List CardpackBannerList { get; set; } = new(); [JsonPropertyName("gacha_detail")] [Key("gacha_detail")] public string GachaDetail { get; set; } = string.Empty; [JsonPropertyName("child_gacha_info")] [Key("child_gacha_info")] public List ChildGachaInfo { get; set; } = new(); [JsonPropertyName("open_count")] [Key("open_count")] public int OpenCount { get; set; } [JsonPropertyName("open_count_limit")] [Key("open_count_limit")] public int OpenCountLimit { get; set; } [JsonPropertyName("is_hide")] [Key("is_hide")] public int IsHide { get; set; } [JsonPropertyName("pack_category")] [Key("pack_category")] public int PackCategory { get; set; } /// /// Null when the pack has no gacha-point participation. The key MUST be present on the wire /// (explicit null) — client at PackInfoTask.cs:126 does if (jsonData2["gacha_point"] != null), /// a direct LitJson key access that throws KeyNotFoundException when the key is absent /// (only protects against null *value*, not missing *key*). Override the global /// WhenWritingNull per [[project_wire_null_policy]] memory. /// [JsonPropertyName("gacha_point")] [JsonIgnore(Condition = JsonIgnoreCondition.Never)] [Key("gacha_point")] public PackGachaPointDto? GachaPoint { get; set; } [JsonPropertyName("is_pre_release")] [Key("is_pre_release")] public bool IsPreRelease { get; set; } [JsonPropertyName("exists_purchase_reward")] [Key("exists_purchase_reward")] public bool ExistsPurchaseReward { get; set; } [JsonPropertyName("is_new")] [Key("is_new")] public bool IsNew { get; set; } /// /// Prod sends an object {"sales_period_time":"..."} when set and an array [] /// when unset. v1 always emits an empty object when the field is null on the entity — /// matches the active-window case and the client tolerates both shapes via /// ShopExpirtyInfo's LitJson parser. Revisit if a capture proves otherwise. /// /// TODO(2026-05-28): the prod tutorial capture has each active pack with /// "sales_period_info": {"sales_period_time": "<complete_date>"} — i.e., the /// pack's complete_date echoed inside the object. Our controller emits {} /// which the client tolerates (the tutorial flow doesn't filter on this field), but for /// wire fidelity we should populate it from PackConfigEntry.CompleteDate. While /// doing that, also retype this field from Dictionary<string, string?> to a /// typed PackSalesPeriodInfoDto { string SalesPeriodTime } — the current dict /// shape is the lazy-key anti-pattern documented in /// feedback_no_lazy_response_dicts. Deferred from the tutorial-bringup pass /// because it doesn't gate any observable flow. /// [JsonPropertyName("sales_period_info")] [Key("sales_period_info")] public Dictionary SalesPeriodInfo { get; set; } = new(); [JsonPropertyName("poster_type")] [Key("poster_type")] public int PosterType { get; set; } }