import { apiRequest } from "@/shared/api/request"; import { API_ENDPOINTS, API_OPERATIONS, apiEndpointPath } from "@/shared/api/generated/endpoints"; import type { ApiPage, PageQuery } from "@/shared/api/types"; export interface LuckyGiftTierDto { pool: string; tierId: string; rewardCoins: number; weight: number; highWaterOnly: boolean; enabled: boolean; } export interface LuckyGiftConfigDto { appCode?: string; enabled: boolean; ruleVersion: number; giftPrice: number; targetRTPPPM: number; poolRatePPM: number; globalWindowDraws: number; giftWindowDraws: number; noviceDrawLimit: number; intermediateDrawLimit: number; highMultiplier: number; highWaterPoolMultiple: number; platformPoolWeightPPM: number; roomPoolWeightPPM: number; giftPoolWeightPPM: number; initialPlatformPool: number; initialGiftPool: number; initialRoomPool: number; platformReserve: number; giftReserve: number; roomReserve: number; maxSinglePayout: number; userHourlyPayoutCap: number; userDailyPayoutCap: number; deviceDailyPayoutCap: number; roomHourlyPayoutCap: number; anchorDailyPayoutCap: number; roomAtmosphereRatePPM: number; roomAtmosphereInitial: number; roomAtmosphereReserve: number; activityBudget: number; activityDailyLimit: number; largeTierEnabled: boolean; tiers: LuckyGiftTierDto[]; updatedByAdminId?: number; createdAtMs?: number; updatedAtMs?: number; } export interface LuckyGiftConfigPayload { enabled: boolean; gift_price: number; target_rtp_ppm: number; pool_rate_ppm: number; global_window_draws: number; gift_window_draws: number; novice_draw_limit: number; intermediate_draw_limit: number; high_multiplier: number; high_water_pool_multiple: number; platform_pool_weight_ppm: number; room_pool_weight_ppm: number; gift_pool_weight_ppm: number; initial_platform_pool: number; initial_gift_pool: number; initial_room_pool: number; platform_reserve: number; gift_reserve: number; room_reserve: number; max_single_payout: number; user_hourly_payout_cap: number; user_daily_payout_cap: number; device_daily_payout_cap: number; room_hourly_payout_cap: number; anchor_daily_payout_cap: number; room_atmosphere_rate_ppm: number; room_atmosphere_initial: number; room_atmosphere_reserve: number; activity_budget: number; activity_daily_limit: number; large_tier_enabled: boolean; tiers: Array<{ pool: string; tier_id: string; reward_coins: number; weight: number; high_water_only: boolean; enabled: boolean; }>; } export interface LuckyGiftDrawDto { drawId: string; commandId?: string; giftId: string; ruleVersion: number; experiencePool: string; selectedTierId: string; baseRewardCoins: number; roomAtmosphereRewardCoins: number; activitySubsidyCoins: number; effectiveRewardCoins: number; budgetSourcesJson?: string; rewardStatus?: string; rtpWindowIndex: number; giftRTPWindowIndex: number; globalBaseRTPPPM: number; giftBaseRTPPPM: number; stageFeedback: boolean; highMultiplier: boolean; createdAtMs?: number; } type RawConfig = LuckyGiftConfigDto & Record; type RawTier = LuckyGiftTierDto & Record; type RawDraw = LuckyGiftDrawDto & Record; export function getLuckyGiftConfig(): Promise { const endpoint = API_ENDPOINTS.getLuckyGiftConfig; return apiRequest(apiEndpointPath(API_OPERATIONS.getLuckyGiftConfig), { method: endpoint.method, }).then(normalizeConfig); } export function updateLuckyGiftConfig(payload: LuckyGiftConfigPayload): Promise { const endpoint = API_ENDPOINTS.upsertLuckyGiftConfig; return apiRequest( apiEndpointPath(API_OPERATIONS.upsertLuckyGiftConfig), { body: payload, method: endpoint.method, }, ).then(normalizeConfig); } export function listLuckyGiftDraws(query: PageQuery = {}): Promise> { const endpoint = API_ENDPOINTS.listLuckyGiftDraws; return apiRequest>(apiEndpointPath(API_OPERATIONS.listLuckyGiftDraws), { method: endpoint.method, query, }).then((page) => ({ ...page, items: (page.items || []).map(normalizeDraw), })); } function normalizeConfig(item: RawConfig): LuckyGiftConfigDto { return { appCode: stringValue(item.appCode ?? item.app_code), enabled: booleanValue(item.enabled), ruleVersion: numberValue(item.ruleVersion ?? item.rule_version), giftPrice: numberValue(item.giftPrice ?? item.gift_price), targetRTPPPM: numberValue(item.targetRTPPPM ?? item.target_rtp_ppm), poolRatePPM: numberValue(item.poolRatePPM ?? item.pool_rate_ppm), globalWindowDraws: numberValue(item.globalWindowDraws ?? item.global_window_draws), giftWindowDraws: numberValue(item.giftWindowDraws ?? item.gift_window_draws), noviceDrawLimit: numberValue(item.noviceDrawLimit ?? item.novice_draw_limit), intermediateDrawLimit: numberValue(item.intermediateDrawLimit ?? item.intermediate_draw_limit), highMultiplier: numberValue(item.highMultiplier ?? item.high_multiplier), highWaterPoolMultiple: numberValue(item.highWaterPoolMultiple ?? item.high_water_pool_multiple), platformPoolWeightPPM: numberValue(item.platformPoolWeightPPM ?? item.platform_pool_weight_ppm), roomPoolWeightPPM: numberValue(item.roomPoolWeightPPM ?? item.room_pool_weight_ppm), giftPoolWeightPPM: numberValue(item.giftPoolWeightPPM ?? item.gift_pool_weight_ppm), initialPlatformPool: numberValue(item.initialPlatformPool ?? item.initial_platform_pool), initialGiftPool: numberValue(item.initialGiftPool ?? item.initial_gift_pool), initialRoomPool: numberValue(item.initialRoomPool ?? item.initial_room_pool), platformReserve: numberValue(item.platformReserve ?? item.platform_reserve), giftReserve: numberValue(item.giftReserve ?? item.gift_reserve), roomReserve: numberValue(item.roomReserve ?? item.room_reserve), maxSinglePayout: numberValue(item.maxSinglePayout ?? item.max_single_payout), userHourlyPayoutCap: numberValue(item.userHourlyPayoutCap ?? item.user_hourly_payout_cap), userDailyPayoutCap: numberValue(item.userDailyPayoutCap ?? item.user_daily_payout_cap), deviceDailyPayoutCap: numberValue(item.deviceDailyPayoutCap ?? item.device_daily_payout_cap), roomHourlyPayoutCap: numberValue(item.roomHourlyPayoutCap ?? item.room_hourly_payout_cap), anchorDailyPayoutCap: numberValue(item.anchorDailyPayoutCap ?? item.anchor_daily_payout_cap), roomAtmosphereRatePPM: numberValue(item.roomAtmosphereRatePPM ?? item.room_atmosphere_rate_ppm), roomAtmosphereInitial: numberValue(item.roomAtmosphereInitial ?? item.room_atmosphere_initial), roomAtmosphereReserve: numberValue(item.roomAtmosphereReserve ?? item.room_atmosphere_reserve), activityBudget: numberValue(item.activityBudget ?? item.activity_budget), activityDailyLimit: numberValue(item.activityDailyLimit ?? item.activity_daily_limit), largeTierEnabled: booleanValue(item.largeTierEnabled ?? item.large_tier_enabled), tiers: arrayValue(item.tiers).map(normalizeTier), updatedByAdminId: numberValue(item.updatedByAdminId ?? item.updated_by_admin_id), createdAtMs: numberValue(item.createdAtMs ?? item.created_at_ms), updatedAtMs: numberValue(item.updatedAtMs ?? item.updated_at_ms), }; } function normalizeTier(raw: unknown): LuckyGiftTierDto { const item = asRecord(raw) as RawTier; return { pool: stringValue(item.pool), tierId: stringValue(item.tierId ?? item.tier_id), rewardCoins: numberValue(item.rewardCoins ?? item.reward_coins), weight: numberValue(item.weight), highWaterOnly: booleanValue(item.highWaterOnly ?? item.high_water_only), enabled: booleanValue(item.enabled), }; } function normalizeDraw(item: RawDraw): LuckyGiftDrawDto { return { drawId: stringValue(item.drawId ?? item.draw_id), commandId: stringValue(item.commandId ?? item.command_id), giftId: stringValue(item.giftId ?? item.gift_id), ruleVersion: numberValue(item.ruleVersion ?? item.rule_version), experiencePool: stringValue(item.experiencePool ?? item.experience_pool), selectedTierId: stringValue(item.selectedTierId ?? item.selected_tier_id), baseRewardCoins: numberValue(item.baseRewardCoins ?? item.base_reward_coins), roomAtmosphereRewardCoins: numberValue( item.roomAtmosphereRewardCoins ?? item.room_atmosphere_reward_coins, ), activitySubsidyCoins: numberValue(item.activitySubsidyCoins ?? item.activity_subsidy_coins), effectiveRewardCoins: numberValue(item.effectiveRewardCoins ?? item.effective_reward_coins), budgetSourcesJson: stringValue(item.budgetSourcesJson ?? item.budget_sources_json), rewardStatus: stringValue(item.rewardStatus ?? item.reward_status), rtpWindowIndex: numberValue(item.rtpWindowIndex ?? item.rtp_window_index), giftRTPWindowIndex: numberValue(item.giftRTPWindowIndex ?? item.gift_rtp_window_index), globalBaseRTPPPM: numberValue(item.globalBaseRTPPPM ?? item.global_base_rtp_ppm), giftBaseRTPPPM: numberValue(item.giftBaseRTPPPM ?? item.gift_base_rtp_ppm), stageFeedback: booleanValue(item.stageFeedback ?? item.stage_feedback), highMultiplier: booleanValue(item.highMultiplier ?? item.high_multiplier), createdAtMs: numberValue(item.createdAtMs ?? item.created_at_ms), }; } function asRecord(value: unknown): Record { return value && typeof value === "object" && !Array.isArray(value) ? (value as Record) : {}; } function arrayValue(value: unknown): unknown[] { return Array.isArray(value) ? value : []; } function booleanValue(value: unknown) { return value === true || value === "true" || value === 1 || value === "1"; } function stringValue(value: unknown) { return typeof value === "string" ? value : value === undefined || value === null ? "" : String(value); } function numberValue(value: unknown) { const number = Number(value || 0); return Number.isFinite(number) ? number : 0; }