import { Server } from 'socket.io' import Logger, { LoggerType } from '#application/logger' import SocketManager from '#managers/socketManager' import WorldRepository from '#repositories/worldRepository' import WorldService from '#services/worldService' class DateManager { private static readonly CONFIG = { GAME_SPEED: 8, // 24 game hours / 3 real hours UPDATE_INTERVAL: 1000 // 1 second } as const private io: Server | null = null private intervalId: NodeJS.Timeout | null = null private currentDate = new Date() private readonly logger = Logger.type(LoggerType.APP) public async boot(): Promise { this.io = SocketManager.getIO() await this.loadDate() this.startDateLoop() this.logger.info('Date manager loaded') } public getCurrentDate(): Date { return this.currentDate } public async setTime(timeString: string): Promise { try { const newDate = this.parseTimeString(timeString) if (!newDate) return this.currentDate = newDate this.emitDate() await this.saveDate() } catch (error) { this.handleError('Failed to set time', error) throw error } } public cleanup(): void { this.intervalId && clearInterval(this.intervalId) } private async loadDate(): Promise { try { const worldRepository = new WorldRepository() const world = await worldRepository.getFirst() this.currentDate = world?.date ?? new Date() } catch (error) { this.handleError('Failed to load date', error) this.currentDate = new Date() } } private parseTimeString(timeString: string): Date | null { const timeOnlyPattern = /^\d{1,2}:\d{2}(:\d{2})?$/ if (timeOnlyPattern.test(timeString)) { const [hours, minutes] = timeString.split(':').map(Number) const newDate = new Date(this.currentDate) newDate.setHours(hours, minutes) return newDate } const fullDate = new Date(timeString) return isNaN(fullDate.getTime()) ? null : fullDate } private startDateLoop(): void { this.intervalId = setInterval(() => { this.advanceGameTime() this.emitDate() void this.saveDate() }, DateManager.CONFIG.UPDATE_INTERVAL) } private advanceGameTime(): void { const advanceMilliseconds = DateManager.CONFIG.GAME_SPEED * DateManager.CONFIG.UPDATE_INTERVAL this.currentDate = new Date(this.currentDate.getTime() + advanceMilliseconds) } private emitDate(): void { this.io?.emit('date', this.currentDate) } private async saveDate(): Promise { try { const worldRepository = new WorldRepository() await (await worldRepository.getFirst())?.setDate(this.currentDate).save() } catch (error) { this.handleError('Failed to save date', error) } } private handleError(message: string, error: unknown): void { this.logger.error(`${message}: ${error instanceof Error ? error.message : String(error)}`) } } export default new DateManager()