import type { AdvanceLocalPuzzleNextLevelRequest, PuzzleRunResponse, StartPuzzleRunRequest, SubmitPuzzleLeaderboardRequest, SwapPuzzlePiecesRequest, UpdatePuzzleRuntimePauseRequest, UsePuzzleRuntimePropRequest, } from '../../../packages/shared/src/contracts/puzzleRuntimeSession'; import { type ApiRetryOptions, requestJson } from '../apiClient'; const PUZZLE_RUNTIME_API_BASE = '/api/runtime/puzzle/runs'; const PUZZLE_RUNTIME_READ_RETRY: ApiRetryOptions = { maxRetries: 1, baseDelayMs: 120, maxDelayMs: 360, }; const PUZZLE_RUNTIME_WRITE_RETRY: ApiRetryOptions = { maxRetries: 1, baseDelayMs: 120, maxDelayMs: 360, retryUnsafeMethods: true, }; /** * 从某个已发布拼图作品开始一次 run。 */ export async function startPuzzleRun(payload: StartPuzzleRunRequest) { return requestJson( PUZZLE_RUNTIME_API_BASE, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }, '启动拼图玩法失败', { retry: PUZZLE_RUNTIME_WRITE_RETRY, }, ); } /** * 读取拼图运行态快照。 */ export async function getPuzzleRun(runId: string) { return requestJson( `${PUZZLE_RUNTIME_API_BASE}/${encodeURIComponent(runId)}`, { method: 'GET', }, '读取拼图运行快照失败', { retry: PUZZLE_RUNTIME_READ_RETRY, }, ); } /** * 提交两块交换请求。 */ export async function swapPuzzlePieces( runId: string, payload: SwapPuzzlePiecesRequest, ) { return requestJson( `${PUZZLE_RUNTIME_API_BASE}/${encodeURIComponent(runId)}/swap`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }, '交换拼图块失败', { retry: PUZZLE_RUNTIME_WRITE_RETRY, }, ); } /** * 进入推荐出的下一关。 */ export async function advancePuzzleNextLevel(runId: string) { return requestJson( `${PUZZLE_RUNTIME_API_BASE}/${encodeURIComponent(runId)}/next-level`, { method: 'POST', }, '进入下一关失败', { retry: PUZZLE_RUNTIME_WRITE_RETRY, }, ); } /** * 提交通关成绩并读取真实排行榜。 */ export async function submitPuzzleLeaderboard( runId: string, payload: SubmitPuzzleLeaderboardRequest, ) { return requestJson( `${PUZZLE_RUNTIME_API_BASE}/${encodeURIComponent(runId)}/leaderboard`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }, '提交拼图排行榜失败', { retry: PUZZLE_RUNTIME_WRITE_RETRY, }, ); } /** * 暂停或恢复正式拼图运行态计时。 */ export async function updatePuzzleRunPause( runId: string, payload: UpdatePuzzleRuntimePauseRequest, ) { return requestJson( `${PUZZLE_RUNTIME_API_BASE}/${encodeURIComponent(runId)}/pause`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }, '更新拼图计时状态失败', { retry: PUZZLE_RUNTIME_WRITE_RETRY, }, ); } /** * 使用正式拼图道具,服务端负责扣除光点并更新运行态。 */ export async function usePuzzleRuntimeProp( runId: string, payload: UsePuzzleRuntimePropRequest, ) { return requestJson( `${PUZZLE_RUNTIME_API_BASE}/${encodeURIComponent(runId)}/props`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }, '使用拼图道具失败', { retry: PUZZLE_RUNTIME_WRITE_RETRY, }, ); } /** * 单机运行态进入下一关,图片来源选择全部由后端裁决。 */ export async function advanceLocalPuzzleNextLevel( payload: AdvanceLocalPuzzleNextLevelRequest, ) { return requestJson( `${PUZZLE_RUNTIME_API_BASE}/local-next-level`, { method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload), }, '进入下一关失败', { retry: PUZZLE_RUNTIME_WRITE_RETRY, }, ); } export const puzzleRuntimeClient = { advanceLocalNextLevel: advanceLocalPuzzleNextLevel, advanceNextLevel: advancePuzzleNextLevel, getRun: getPuzzleRun, submitLeaderboard: submitPuzzleLeaderboard, startRun: startPuzzleRun, updatePause: updatePuzzleRunPause, useProp: usePuzzleRuntimeProp, };