import { apiRequest } from "@/shared/api/request"; import { API_ENDPOINTS, API_OPERATIONS, apiEndpointPath } from "@/shared/api/generated/endpoints"; import type { QueryParams } from "@/shared/api/request"; export interface GamePlatformDto { appCode?: string; platformCode: string; platformName: string; status: string; apiBaseUrl: string; // 服务端按 adapterType 选择真实厂商协议:yomi_v4/leadercc_v1/zeeone_v1/baishun_v1/vivagames_v1/reyou_v1。 adapterType: string; // callbackSecret 由后台列表返回,用于配置页直接核对和轮换厂商 key。 callbackSecret?: string; callbackSecretSet: boolean; callbackIpWhitelist: string[]; // 厂商扩展配置保留 JSON 字符串,后台前端不绑定具体字段结构。 adapterConfigJson: string; sortOrder: number; createdAtMs?: number; updatedAtMs?: number; } export interface GameCatalogDto { appCode?: string; gameId: string; platformCode: string; providerGameId: string; gameName: string; category: string; iconUrl: string; coverUrl: string; launchUrl?: string; launchMode: string; orientation: string; safeHeight: number; minCoin: number; status: string; sortOrder: number; tags: string[]; createdAtMs?: number; updatedAtMs?: number; } export interface GameCatalogPage { items: GameCatalogDto[]; nextCursor?: string; pageSize?: number; serverTimeMs?: number; total?: number; totalPages?: number; } export interface GamePlatformPage { items: GamePlatformDto[]; serverTimeMs?: number; } export interface GameSyncPayload { dryRun?: boolean; status?: string; category?: string; launchMode?: string; minCoin?: number; tags?: string[]; gameListType?: number; providerGameIds?: string[]; } export interface GameSyncResult { platformCode: string; synced: number; dryRun: boolean; items: GameCatalogDto[]; } export interface DiceStakeOptionDto { stakeCoin: number; enabled: boolean; sortOrder: number; } export interface DiceConfigDto { appCode?: string; gameId: string; status: string; stakeOptions: DiceStakeOptionDto[]; feeBps: number; poolBps: number; minPlayers: number; maxPlayers: number; robotEnabled: boolean; robotMatchWaitMs: number; poolBalanceCoin: number; createdAtMs?: number; updatedAtMs?: number; } export interface DiceRobotDto { appCode?: string; gameId: string; userId: string; userIdNumber?: number; shortId?: string; nickname?: string; avatar?: string; status: string; createdByAdminId?: number; createdAtMs?: number; updatedAtMs?: number; } export interface DiceRobotPage { items: DiceRobotDto[]; nextCursor?: string; pageSize?: number; serverTimeMs?: number; } export type DiceConfigPayload = Omit; export interface DicePoolAdjustPayload { amountCoin: number; direction: "in" | "out"; reason: string; } export interface DiceGenerateRobotsPayload { count: number; nicknameLanguage?: "english" | "arabic"; avatarUrls?: string[]; country?: string; gender?: string; } export type GamePlatformPayload = Omit< GamePlatformDto, "appCode" | "createdAtMs" | "updatedAtMs" | "callbackSecretSet" >; export type GameCatalogPayload = Omit; export interface GameCatalogQuery { platformCode?: string; status?: string; pageSize?: number; cursor?: string; } export function listGamePlatforms(status = ""): Promise { const endpoint = API_ENDPOINTS.listPlatforms; return apiRequest(apiEndpointPath(API_OPERATIONS.listPlatforms), { method: endpoint.method, query: { status }, }).then((page) => ({ ...page, items: (page.items || []).map(normalizePlatform), })); } export function upsertGamePlatform(payload: GamePlatformPayload, platformCode = ""): Promise { const operation = platformCode ? API_OPERATIONS.updatePlatform : API_OPERATIONS.createPlatform; const endpoint = API_ENDPOINTS[operation]; return apiRequest( apiEndpointPath(operation, platformCode ? { platform_code: platformCode } : {}), { body: payload, method: endpoint.method, }, ).then(normalizePlatform); } export function listGameCatalog(query: GameCatalogQuery = {}): Promise { const endpoint = API_ENDPOINTS.listCatalog; return apiRequest(apiEndpointPath(API_OPERATIONS.listCatalog), { method: endpoint.method, query: query as QueryParams, }).then((page) => ({ ...page, items: (page.items || []).map(normalizeCatalog), })); } export function upsertGameCatalog(payload: GameCatalogPayload, gameId = ""): Promise { const operation = gameId ? API_OPERATIONS.updateCatalog : API_OPERATIONS.createCatalog; const endpoint = API_ENDPOINTS[operation]; return apiRequest( apiEndpointPath(operation, gameId ? { game_id: gameId } : {}), { body: payload, method: endpoint.method, }, ).then(normalizeCatalog); } export function setGameStatus(gameId: string, status: string): Promise { const endpoint = API_ENDPOINTS.setGameStatus; return apiRequest( apiEndpointPath(API_OPERATIONS.setGameStatus, { game_id: gameId }), { body: { status }, method: endpoint.method, }, ).then(normalizeCatalog); } export function deleteGameCatalog(gameId: string): Promise { const endpoint = API_ENDPOINTS.deleteCatalog; return apiRequest(apiEndpointPath(API_OPERATIONS.deleteCatalog, { game_id: gameId }), { method: endpoint.method, }); } export function syncGamePlatformCatalog(platformCode: string, payload: GameSyncPayload = {}): Promise { return apiRequest( `/v1/admin/game/platforms/${encodeURIComponent(platformCode)}/sync-games`, { body: payload, method: "POST", }, ).then((result) => ({ ...result, items: (result.items || []).map(normalizeCatalog), synced: numberValue(result.synced), dryRun: Boolean(result.dryRun), })); } export function listSelfGames(): Promise<{ items: DiceConfigDto[]; serverTimeMs?: number }> { const endpoint = API_ENDPOINTS.listSelfGames; return apiRequest<{ items: DiceConfigDto[]; serverTimeMs?: number }>(apiEndpointPath(API_OPERATIONS.listSelfGames), { method: endpoint.method, }).then((page) => ({ ...page, items: (page.items || []).map(normalizeDiceConfig), })); } export function updateDiceConfig(gameId: string, payload: DiceConfigPayload): Promise { const endpoint = API_ENDPOINTS.updateDiceConfig; return apiRequest( apiEndpointPath(API_OPERATIONS.updateDiceConfig, { game_id: gameId }), { body: payload, method: endpoint.method }, ).then(normalizeDiceConfig); } export function adjustDicePool( gameId: string, payload: DicePoolAdjustPayload, ): Promise<{ config: DiceConfigDto; adjustment: unknown }> { const endpoint = API_ENDPOINTS.adjustDicePool; return apiRequest<{ config: DiceConfigDto; adjustment: unknown }, DicePoolAdjustPayload>( apiEndpointPath(API_OPERATIONS.adjustDicePool, { game_id: gameId }), { body: payload, method: endpoint.method }, ).then((result) => ({ ...result, config: normalizeDiceConfig(result.config || {}) })); } export function listDiceRobots(query: { gameId?: string; status?: string; pageSize?: number; cursor?: string } = {}) { const endpoint = API_ENDPOINTS.listDiceRobots; return apiRequest(apiEndpointPath(API_OPERATIONS.listDiceRobots), { method: endpoint.method, query: query as QueryParams, }).then((page) => ({ ...page, items: (page.items || []).map(normalizeDiceRobot), })); } export function generateDiceRobots(payload: DiceGenerateRobotsPayload) { const endpoint = API_ENDPOINTS.generateDiceRobots; return apiRequest<{ created: number; items: DiceRobotDto[] }, DiceGenerateRobotsPayload>( apiEndpointPath(API_OPERATIONS.generateDiceRobots), { body: payload, method: endpoint.method }, ).then((result) => ({ ...result, items: (result.items || []).map(normalizeDiceRobot) })); } export function setDiceRobotStatus(userId: string, status: string, gameId = "dice") { const endpoint = API_ENDPOINTS.setDiceRobotStatus; return apiRequest( apiEndpointPath(API_OPERATIONS.setDiceRobotStatus, { user_id: userId }), { body: { status }, method: endpoint.method, query: { gameId } }, ).then(normalizeDiceRobot); } export function deleteDiceRobot(userId: string, gameId = "dice"): Promise<{ deleted: boolean }> { const endpoint = API_ENDPOINTS.deleteDiceRobot; return apiRequest<{ deleted: boolean }>(apiEndpointPath(API_OPERATIONS.deleteDiceRobot, { user_id: userId }), { method: endpoint.method, query: { gameId }, }); } function normalizePlatform(platform: Partial): GamePlatformDto { return { appCode: stringValue(platform.appCode), platformCode: stringValue(platform.platformCode), platformName: stringValue(platform.platformName), status: stringValue(platform.status || "active"), apiBaseUrl: stringValue(platform.apiBaseUrl), adapterType: stringValue(platform.adapterType || "yomi_v4"), callbackSecret: stringValue(platform.callbackSecret), callbackSecretSet: Boolean(platform.callbackSecretSet), callbackIpWhitelist: Array.isArray(platform.callbackIpWhitelist) ? platform.callbackIpWhitelist.map(String).filter(Boolean) : [], adapterConfigJson: stringValue(platform.adapterConfigJson || "{}"), sortOrder: numberValue(platform.sortOrder), createdAtMs: numberValue(platform.createdAtMs), updatedAtMs: numberValue(platform.updatedAtMs), }; } function normalizeCatalog(game: Partial): GameCatalogDto { return { appCode: stringValue(game.appCode), gameId: stringValue(game.gameId), platformCode: stringValue(game.platformCode), providerGameId: stringValue(game.providerGameId), gameName: stringValue(game.gameName), category: stringValue(game.category), iconUrl: stringValue(game.iconUrl), coverUrl: stringValue(game.coverUrl), launchUrl: stringValue(game.launchUrl), launchMode: normalizeLaunchMode(game.launchMode), orientation: stringValue(game.orientation || "portrait"), safeHeight: numberValue(game.safeHeight), minCoin: numberValue(game.minCoin), status: stringValue(game.status || "active"), sortOrder: numberValue(game.sortOrder), tags: Array.isArray(game.tags) ? game.tags.map(String).filter(Boolean) : [], createdAtMs: numberValue(game.createdAtMs), updatedAtMs: numberValue(game.updatedAtMs), }; } function normalizeDiceConfig(config: Partial): DiceConfigDto { return { appCode: stringValue(config.appCode), gameId: stringValue(config.gameId || "dice"), status: stringValue(config.status || "active"), stakeOptions: Array.isArray(config.stakeOptions) ? config.stakeOptions.map((item) => ({ stakeCoin: numberValue(item.stakeCoin), enabled: item.enabled !== false, sortOrder: numberValue(item.sortOrder), })) : [], feeBps: numberValue(config.feeBps), poolBps: numberValue(config.poolBps), minPlayers: numberValue(config.minPlayers || 2), maxPlayers: numberValue(config.maxPlayers || 2), robotEnabled: config.robotEnabled !== false, robotMatchWaitMs: numberValue(config.robotMatchWaitMs || 3000), poolBalanceCoin: numberValue(config.poolBalanceCoin), createdAtMs: numberValue(config.createdAtMs), updatedAtMs: numberValue(config.updatedAtMs), }; } function normalizeDiceRobot(robot: Partial): DiceRobotDto { return { appCode: stringValue(robot.appCode), gameId: stringValue(robot.gameId || "dice"), userId: stringValue(robot.userId), userIdNumber: numberValue(robot.userIdNumber), shortId: stringValue(robot.shortId), nickname: stringValue(robot.nickname), avatar: stringValue(robot.avatar), status: stringValue(robot.status || "active"), createdByAdminId: numberValue(robot.createdByAdminId), createdAtMs: numberValue(robot.createdAtMs), updatedAtMs: numberValue(robot.updatedAtMs), }; } 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; } function normalizeLaunchMode(value: unknown) { const mode = stringValue(value); return mode === "half_screen" || mode === "three_quarter_screen" || mode === "full_screen" ? mode : "full_screen"; }