// src/main/ipc/history-handlers.ts import { ipcMain } from 'electron' import { IPC_CHANNELS } from '@d3ro/core/ipc-channels' import { ipcSuccess, ipcError, ErrorCode } from '@d3ro/core/errors' import fs from 'fs' import { getHistoryService } from '../services/HistoryService' import { getCloudSyncService } from '../services/CloudSyncService' import { audioMimeType } from '../services/sync/audio-sync' import type { HistoryQueryParams, HistoryGetByIdParams, HistoryDeleteParams, HistorySearchParams, HistorySetFavoriteParams, HistoryAudioSource } from '@d3ro/core/types' /** 렌더러로 넘기는 로컬 녹음 상한. 넘으면 재생하지 않는다(IPC 복사 비용). */ const MAX_LOCAL_AUDIO_BYTES = 100 * 1024 * 1024 export function registerHistoryHandlers(): void { ipcMain.handle(IPC_CHANNELS.HISTORY.GET_ALL, async (_event, params: HistoryQueryParams) => { try { return ipcSuccess(getHistoryService().list(params)) } catch (error) { const message = error instanceof Error ? error.message : String(error) return ipcError(ErrorCode.DBQueryFailed, `Failed to get history: ${message}`) } }) ipcMain.handle(IPC_CHANNELS.HISTORY.GET_BY_ID, async (_event, params: HistoryGetByIdParams) => { try { return ipcSuccess(getHistoryService().getById(params.id)) } catch (error) { const message = error instanceof Error ? error.message : String(error) return ipcError(ErrorCode.DBQueryFailed, `Failed to get history entry: ${message}`) } }) ipcMain.handle(IPC_CHANNELS.HISTORY.DELETE, async (_event, params: HistoryDeleteParams) => { try { const removed = getHistoryService().delete(params.id) if (!removed) { return ipcError(ErrorCode.HistoryNotFound, `History entry not found: ${params.id}`) } return ipcSuccess(undefined) } catch (error) { const message = error instanceof Error ? error.message : String(error) return ipcError(ErrorCode.DBWriteFailed, `Failed to delete history entry: ${message}`) } }) ipcMain.handle(IPC_CHANNELS.HISTORY.DELETE_ALL, async () => { try { getHistoryService().deleteAll() return ipcSuccess(undefined) } catch (error) { const message = error instanceof Error ? error.message : String(error) return ipcError(ErrorCode.DBWriteFailed, `Failed to delete all history: ${message}`) } }) ipcMain.handle(IPC_CHANNELS.HISTORY.SET_FAVORITE, async (_event, params: HistorySetFavoriteParams) => { try { const entry = getHistoryService().setFavorite(params.id, params.isFavorite === true) if (!entry) { return ipcError(ErrorCode.HistoryNotFound, `History entry not found: ${params.id}`) } return ipcSuccess(entry) } catch (error) { const message = error instanceof Error ? error.message : String(error) return ipcError(ErrorCode.DBWriteFailed, `Failed to update favorite: ${message}`) } }) ipcMain.handle(IPC_CHANNELS.HISTORY.GET_AUDIO, async (_event, params: HistoryGetByIdParams) => { try { const entry = getHistoryService().getById(params.id) if (!entry) return ipcError(ErrorCode.HistoryNotFound, `History entry not found: ${params.id}`) const localPath = entry.audioLocalPath if (localPath && fs.existsSync(localPath) && fs.statSync(localPath).size <= MAX_LOCAL_AUDIO_BYTES) { const source: HistoryAudioSource = { kind: 'local', bytes: new Uint8Array(fs.readFileSync(localPath)), mimeType: audioMimeType(localPath) ?? 'audio/wav', } return ipcSuccess(source) } const url = await getCloudSyncService().createHistoryAudioUrl(params.id) return ipcSuccess(url ? ({ kind: 'remote', url } satisfies HistoryAudioSource) : null) } catch (error) { const message = error instanceof Error ? error.message : String(error) return ipcError(ErrorCode.DBQueryFailed, `Failed to load audio: ${message}`) } }) ipcMain.handle(IPC_CHANNELS.HISTORY.SEARCH, async (_event, params: HistorySearchParams) => { try { return ipcSuccess(getHistoryService().search(params)) } catch (error) { const message = error instanceof Error ? error.message : String(error) return ipcError(ErrorCode.DBQueryFailed, `Failed to search history: ${message}`) } }) ipcMain.handle(IPC_CHANNELS.STATS.GET_SUMMARY, async () => { try { return ipcSuccess(getHistoryService().getStats()) } catch (error) { const message = error instanceof Error ? error.message : String(error) return ipcError(ErrorCode.DBQueryFailed, `Failed to get stats: ${message}`) } }) }