import { Body, Controller, Get, Param, Post, Query } from "@nestjs/common"; import type { EmotionTag } from "@kokorone/shared"; import { ScheduleService } from "./schedule.service.js"; import { ScheduleExceptionService } from "./schedule-exception.service.js"; import { ScheduleEmotionBaselineService } from "./schedule-emotion-baseline.service.js"; import { OfflineEventService } from "./offline-event.service.js"; import { PrismaService } from "../prisma/prisma.service.js"; import { availabilityForStatus } from "./constants.js"; interface SpecialDayBody { date: string; label: string; } interface ExceptionBody { userId: string; mode: "NORMAL" | "BRIEF" | "DELAYED" | "NO_REPLY"; intimacy: number; dominantEmotion: EmotionTag; userInput: string; now?: string; } @Controller("schedule") export class ScheduleController { constructor( private readonly schedule: ScheduleService, private readonly exception: ScheduleExceptionService, private readonly baseline: ScheduleEmotionBaselineService, private readonly offlineEvent: OfflineEventService, private readonly prisma: PrismaService, ) {} @Post(":characterId/seed-default") async seedDefault(@Param("characterId") characterId: string) { await this.schedule.seedDefaultSchedule(characterId); return { ok: true }; } @Post(":characterId/special-days") async addSpecialDay(@Param("characterId") characterId: string, @Body() body: SpecialDayBody) { return this.prisma.client.specialDay.create({ data: { characterId, date: new Date(body.date), label: body.label }, }); } @Get(":characterId/info") async getInfo(@Param("characterId") characterId: string, @Query("now") now?: string) { const info = await this.schedule.getInfo(characterId, now ? new Date(now) : undefined); return { ...info, availability: availabilityForStatus(info.slot?.status ?? null) }; } @Post(":characterId/exception") async tryException(@Param("characterId") characterId: string, @Body() body: ExceptionBody) { const exceptionType = await this.exception.tryApply( characterId, body.userId, body.mode, { intimacy: body.intimacy, dominantEmotion: body.dominantEmotion, userInput: body.userInput }, body.now ? new Date(body.now) : undefined, ); return { exceptionType }; } @Get(":characterId/baseline") async getBaseline(@Param("characterId") characterId: string, @Query("now") now?: string) { const baseline = await this.baseline.computeBaseline(characterId, now ? new Date(now) : undefined); return { baseline }; } @Post(":characterId/offline-event") async generateOfflineEvent(@Param("characterId") characterId: string, @Body() body: { now?: string }) { await this.offlineEvent.maybeGenerate(characterId, body.now ? new Date(body.now) : undefined); return { ok: true }; } }