import { ipcMain, dialog, app } from 'electron' import { copyFileSync, mkdirSync } from 'fs' import { extname, join } from 'path' import { IPC } from '../../../shared/ipc-channels' import type { CreateBookParams, UpdateBookMetaParams } from '../../../shared/types' import { BookRegistryService } from '../../services/book-registry' import type { WritingSessionService } from '../../services/writing-session.service' import { wrap } from '../result' let previousBookId: string | null = null export function registerBookHandlers( registry: BookRegistryService, writingSessions?: WritingSessionService ): void { ipcMain.handle(IPC.BOOK_LIST, () => wrap(() => registry.list())) ipcMain.handle(IPC.BOOK_CREATE, (_event, params: CreateBookParams) => wrap(() => registry.create(params)) ) ipcMain.handle(IPC.BOOK_DELETE, (_event, { bookId }: { bookId: string }) => wrap(() => { registry.delete(bookId) }) ) ipcMain.handle(IPC.BOOK_OPEN, (_event, { bookId }: { bookId: string }) => wrap(() => { if (writingSessions && previousBookId && previousBookId !== bookId) { writingSessions.endActive(previousBookId) } previousBookId = bookId return registry.open(bookId) }) ) ipcMain.handle( IPC.BOOK_UPDATE_META, (_event, { bookId, ...patch }: { bookId: string } & UpdateBookMetaParams) => wrap(() => registry.updateMeta(bookId, patch)) ) ipcMain.handle(IPC.BOOK_PICK_COVER, (_event, { bookId }: { bookId: string }) => wrap(async () => { const { canceled, filePaths } = await dialog.showOpenDialog({ filters: [{ name: 'Images', extensions: ['jpg', 'jpeg', 'png', 'webp'] }], properties: ['openFile'] }) if (canceled || !filePaths[0]) return null const src = filePaths[0] const ext = extname(src).toLowerCase() || '.jpg' const coversDir = join(app.getPath('userData'), 'covers') mkdirSync(coversDir, { recursive: true }) const dest = join(coversDir, `${bookId}${ext}`) copyFileSync(src, dest) return registry.updateMeta(bookId, { coverPath: dest }) }) ) }