import type { AudioContentDetail, AudioContentListItem } from "@/features/audio-contents/model/types"; import { audioContentDetailSchema, audioContentListResponseSchema } from "@/features/audio-contents/model/types"; import { audioContentCreateRequestSchema, audioContentCreateResponseSchema, audioContentDeactivateRequestSchema, audioContentUpdateRequestSchema } from "@/features/audio-contents/schemas/audio-content-schema"; import type { AudioContentCreateRequest, AudioContentCreateResponse, AudioContentDeactivateRequest, AudioContentUpdateRequest } from "@/features/audio-contents/schemas/audio-content-schema"; import type { ApiClient } from "@/shared/api/client"; import type { PageData } from "@/shared/api/pagination"; import { z } from "zod"; export type GetAudioContentsParams = { readonly characterId: string; readonly page?: number; readonly search_word?: string; readonly size?: number; }; export type GetAudioContentParams = { readonly characterId: string; readonly contentId: string; }; export type CreateAudioContentParams = { readonly characterId: string; readonly contentFile: File; readonly coverImage: File; readonly request: AudioContentCreateRequest; }; export type UpdateAudioContentParams = { readonly coverImage?: File; readonly request: AudioContentUpdateRequest; }; const nullSuccessSchema = z.null(); function createAudioContentFormData(contentFile: File | undefined, coverImage: File | undefined, request: object): FormData { const body = new FormData(); if (contentFile !== undefined) { body.append("contentFile", contentFile); } if (coverImage !== undefined) { body.append("coverImage", coverImage); } body.append("request", new Blob([JSON.stringify(request)], { type: "application/json" })); return body; } export function createAudioContentCreateBody(params: CreateAudioContentParams): FormData { return createAudioContentFormData(params.contentFile, params.coverImage, audioContentCreateRequestSchema.parse(params.request)); } export function createAudioContentUpdateBody(params: UpdateAudioContentParams): FormData { return createAudioContentFormData(undefined, params.coverImage, audioContentUpdateRequestSchema.parse(params.request)); } export function createAudioContentDeactivateBody(request: AudioContentDeactivateRequest): FormData { return createAudioContentFormData(undefined, undefined, audioContentDeactivateRequestSchema.parse(request)); } function normalizePage(value: number | undefined): number { return Math.max(0, Math.trunc(value ?? 0)); } function normalizeSize(value: number | undefined): number { return Math.max(1, Math.trunc(value ?? 20)); } export async function getAudioContents(apiClient: ApiClient, params: GetAudioContentsParams): Promise> { const page = normalizePage(params.page); const size = normalizeSize(params.size); const query = new URLSearchParams({ page: String(page), size: String(size) }); const searchWord = params.search_word?.trim(); if (searchWord !== undefined && searchWord.length >= 2) { query.set("search_word", searchWord); } const response = await apiClient.request({ path: `/api/v2/admin/ai-characters/${encodeURIComponent(params.characterId)}/audio-contents?${query.toString()}`, responseSchema: audioContentListResponseSchema, authentication: "required", }); return { totalCount: response.totalCount, page, size, hasNext: (page + 1) * size < response.totalCount, items: response.items, }; } export function getAudioContent(apiClient: ApiClient, params: GetAudioContentParams): Promise { return apiClient.request({ path: `/api/v2/admin/ai-characters/${encodeURIComponent(params.characterId)}/audio-contents/${encodeURIComponent(params.contentId)}`, responseSchema: audioContentDetailSchema, authentication: "required", }); } export function createAudioContent(apiClient: ApiClient, params: CreateAudioContentParams): Promise { return apiClient.request({ path: `/api/v2/admin/ai-characters/${encodeURIComponent(params.characterId)}/audio-contents`, method: "POST", body: createAudioContentCreateBody(params), responseSchema: audioContentCreateResponseSchema, authentication: "required", }); } export function updateAudioContent(apiClient: ApiClient, characterId: string, contentId: string, params: UpdateAudioContentParams): Promise { return apiClient.request({ path: `/api/v2/admin/ai-characters/${encodeURIComponent(characterId)}/audio-contents/${encodeURIComponent(contentId)}`, method: "PUT", body: createAudioContentUpdateBody(params), responseSchema: nullSuccessSchema, authentication: "required", }); } export function deactivateAudioContent(apiClient: ApiClient, characterId: string, contentId: string): Promise { return apiClient.request({ path: `/api/v2/admin/ai-characters/${encodeURIComponent(characterId)}/audio-contents/${encodeURIComponent(contentId)}`, method: "PUT", body: createAudioContentDeactivateBody({ isActive: false }), responseSchema: nullSuccessSchema, authentication: "required", }); }