import { ipcMain } from 'electron'
import { getDatabase } from '../db'
import { createLogger } from '../services/logger'
import { telemetryService } from '../services/telemetry-service'
import {
  setFieldCollectionEnabledCache,
  setMemoryInjectionEnabledCache,
  setBashOutputCaptureEnabledCache,
  setTokenSaverEnabledCache,
  FIELD_COLLECTION_SETTING_KEY,
  MEMORY_INJECTION_SETTING_KEY,
  BASH_OUTPUT_CAPTURE_SETTING_KEY,
  TOKEN_SAVER_ENABLED_SETTING_KEY
} from '../field/privacy'
import type {
  ProjectCreate,
  ProjectUpdate,
  WorktreeCreate,
  WorktreeUpdate,
  SessionCreate,
  SessionUpdate,
  SessionSearchOptions,
  SpaceCreate,
  SpaceUpdate
} from '../db'
import type {
  DiffCommentCreate,
  DiffCommentListOptions,
  DiffCommentUpdate
} from '@shared/types/git'

const log = createLogger({ component: 'DatabaseHandlers' })

export function registerDatabaseHandlers(): void {
  log.info('Registering database handlers')
  // Settings
  ipcMain.handle('db:setting:get', (_event, key: string) => {
    return getDatabase().getSetting(key)
  })

  ipcMain.handle('db:setting:set', (_event, key: string, value: string) => {
    getDatabase().setSetting(key, value)
    // Phase 21: keep the privacy cache synchronized with the DB write, in the
    // same call path, so no event slips through with a stale cached value.
    if (key === FIELD_COLLECTION_SETTING_KEY) {
      setFieldCollectionEnabledCache(value !== 'false')
    }
    // Phase 22C.1: same pattern for memory injection toggle.
    if (key === MEMORY_INJECTION_SETTING_KEY) {
      setMemoryInjectionEnabledCache(value !== 'false')
    }
    // Phase 21.5: same pattern for agent bash output capture toggle.
    // Default OFF — must be literally 'true' to enable.
    if (key === BASH_OUTPUT_CAPTURE_SETTING_KEY) {
      setBashOutputCaptureEnabledCache(value === 'true')
    }
    // v1.5.0: Token Saver master switch. Default ON — only literal 'false' disables.
    if (key === TOKEN_SAVER_ENABLED_SETTING_KEY) {
      setTokenSaverEnabledCache(value !== 'false')
    }
    return true
  })

  ipcMain.handle('db:setting:delete', (_event, key: string) => {
    getDatabase().deleteSetting(key)
    // Phase 21: deleting the setting reverts to the default (enabled).
    if (key === FIELD_COLLECTION_SETTING_KEY) {
      setFieldCollectionEnabledCache(true)
    }
    // Phase 22C.1: same.
    if (key === MEMORY_INJECTION_SETTING_KEY) {
      setMemoryInjectionEnabledCache(true)
    }
    // Phase 21.5: delete reverts bash output capture to default OFF.
    if (key === BASH_OUTPUT_CAPTURE_SETTING_KEY) {
      setBashOutputCaptureEnabledCache(false)
    }
    // v1.5.0: delete reverts Token Saver to default ON.
    if (key === TOKEN_SAVER_ENABLED_SETTING_KEY) {
      setTokenSaverEnabledCache(true)
    }
    return true
  })

  ipcMain.handle('db:setting:getAll', () => {
    return getDatabase().getAllSettings()
  })

  // Projects
  ipcMain.handle('db:project:create', (_event, data: ProjectCreate) => {
    const db = getDatabase()
    const project = db.createProject(data)

    // Create default worktree for the new project
    db.createWorktree({
      project_id: project.id,
      name: '(no-worktree)',
      branch_name: '',
      path: project.path,
      is_default: true
    })

    telemetryService.track('project_added', {})
    return project
  })

  ipcMain.handle('db:project:get', (_event, id: string) => {
    return getDatabase().getProject(id)
  })

  ipcMain.handle('db:project:getByPath', (_event, path: string) => {
    return getDatabase().getProjectByPath(path)
  })

  ipcMain.handle('db:project:getAll', () => {
    return getDatabase().getAllProjects()
  })

  ipcMain.handle('db:project:update', (_event, id: string, data: ProjectUpdate) => {
    return getDatabase().updateProject(id, data)
  })

  ipcMain.handle('db:project:delete', (_event, id: string) => {
    return getDatabase().deleteProject(id)
  })

  ipcMain.handle('db:project:touch', (_event, id: string) => {
    getDatabase().touchProject(id)
    return true
  })

  ipcMain.handle('db:project:reorder', (_event, orderedIds: string[]) => {
    getDatabase().reorderProjects(orderedIds)
    return true
  })

  ipcMain.handle('db:project:sortByLastMessage', () => {
    return getDatabase().getProjectIdsSortedByLastMessage()
  })

  // Worktrees
  ipcMain.handle('db:worktree:create', (_event, data: WorktreeCreate) => {
    return getDatabase().createWorktree(data)
  })

  ipcMain.handle('db:worktree:get', (_event, id: string) => {
    return getDatabase().getWorktree(id)
  })

  ipcMain.handle('db:worktree:getByProject', (_event, projectId: string) => {
    return getDatabase().getWorktreesByProject(projectId)
  })

  ipcMain.handle('db:worktree:getActiveByProject', (_event, projectId: string) => {
    return getDatabase().getActiveWorktreesByProject(projectId)
  })

  ipcMain.handle('db:worktree:getRecentlyActive', (_event, cutoffMs: number) => {
    return getDatabase().getRecentlyActiveWorktrees(cutoffMs)
  })

  ipcMain.handle('db:worktree:update', (_event, id: string, data: WorktreeUpdate) => {
    return getDatabase().updateWorktree(id, data)
  })

  ipcMain.handle('db:worktree:delete', (_event, id: string) => {
    return getDatabase().deleteWorktree(id)
  })

  ipcMain.handle('db:worktree:archive', (_event, id: string) => {
    return getDatabase().archiveWorktree(id)
  })

  ipcMain.handle('db:worktree:touch', (_event, id: string) => {
    getDatabase().touchWorktree(id)
    return true
  })

  ipcMain.handle(
    'db:worktree:updateModel',
    (
      _event,
      {
        worktreeId,
        modelProviderId,
        modelId,
        modelVariant
      }: {
        worktreeId: string
        modelProviderId: string
        modelId: string
        modelVariant: string | null
      }
    ) => {
      try {
        getDatabase().updateWorktreeModel(
          worktreeId,
          modelProviderId,
          modelId,
          modelVariant ?? null
        )
        return { success: true }
      } catch (error) {
        return { success: false, error: error instanceof Error ? error.message : String(error) }
      }
    }
  )

  ipcMain.handle(
    'db:worktree:appendSessionTitle',
    (_event, { worktreeId, title }: { worktreeId: string; title: string }) => {
      try {
        getDatabase().appendSessionTitle(worktreeId, title)
        return { success: true }
      } catch (error) {
        return { success: false, error: error instanceof Error ? error.message : String(error) }
      }
    }
  )

  ipcMain.handle(
    'db:worktree:addAttachment',
    (
      _event,
      {
        worktreeId,
        attachment
      }: {
        worktreeId: string
        attachment: { type: 'jira' | 'figma'; url: string; label: string }
      }
    ) => {
      try {
        return getDatabase().addAttachment(worktreeId, attachment)
      } catch (error) {
        return { success: false, error: error instanceof Error ? error.message : String(error) }
      }
    }
  )

  ipcMain.handle(
    'db:worktree:removeAttachment',
    (_event, { worktreeId, attachmentId }: { worktreeId: string; attachmentId: string }) => {
      try {
        return getDatabase().removeAttachment(worktreeId, attachmentId)
      } catch (error) {
        return { success: false, error: error instanceof Error ? error.message : String(error) }
      }
    }
  )

  ipcMain.handle(
    'db:worktree:attachPR',
    (
      _event,
      { worktreeId, prNumber, prUrl }: { worktreeId: string; prNumber: number; prUrl: string }
    ) => {
      try {
        return getDatabase().attachPR(worktreeId, prNumber, prUrl)
      } catch (error) {
        return { success: false, error: error instanceof Error ? error.message : String(error) }
      }
    }
  )

  ipcMain.handle(
    'db:worktree:detachPR',
    (_event, { worktreeId }: { worktreeId: string }) => {
      try {
        return getDatabase().detachPR(worktreeId)
      } catch (error) {
        return { success: false, error: error instanceof Error ? error.message : String(error) }
      }
    }
  )

  ipcMain.handle(
    'db:worktree:setPinned',
    (_event, { worktreeId, pinned }: { worktreeId: string; pinned: boolean }) => {
      try {
        getDatabase().updateWorktree(worktreeId, { pinned: pinned ? 1 : 0 })
        return { success: true }
      } catch (error) {
        return { success: false, error: error instanceof Error ? error.message : String(error) }
      }
    }
  )

  ipcMain.handle('db:worktree:getPinned', () => {
    const db = getDatabase()
    return db.getPinnedWorktrees()
  })

  // Local diff comments
  ipcMain.handle(
    'db:diffComment:list',
    (_event, { worktreeId, options }: { worktreeId: string; options?: DiffCommentListOptions }) => {
      return getDatabase().getDiffComments(worktreeId, options)
    }
  )

  ipcMain.handle('db:diffComment:create', (_event, data: DiffCommentCreate) => {
    return getDatabase().createDiffComment(data)
  })

  ipcMain.handle(
    'db:diffComment:update',
    (_event, { id, data }: { id: string; data: DiffCommentUpdate }) => {
      return getDatabase().updateDiffComment(id, data)
    }
  )

  ipcMain.handle('db:diffComment:delete', (_event, id: string) => {
    return getDatabase().deleteDiffComment(id)
  })

  // Sessions
  ipcMain.handle('db:session:create', (_event, data: SessionCreate) => {
    return getDatabase().createSession(data)
  })

  ipcMain.handle('db:session:get', (_event, id: string) => {
    return getDatabase().getSession(id)
  })

  ipcMain.handle('db:session:getByWorktree', (_event, worktreeId: string) => {
    return getDatabase().getSessionsByWorktree(worktreeId)
  })

  ipcMain.handle('db:session:getByProject', (_event, projectId: string) => {
    return getDatabase().getSessionsByProject(projectId)
  })

  ipcMain.handle('db:session:getActiveByWorktree', (_event, worktreeId: string) => {
    return getDatabase().getActiveSessionsByWorktree(worktreeId)
  })

  ipcMain.handle('db:session:update', (_event, id: string, data: SessionUpdate) => {
    return getDatabase().updateSession(id, data)
  })

  ipcMain.handle('db:session:delete', (_event, id: string) => {
    // Soft-archive instead of hard delete — sessions are user assets
    return getDatabase().archiveSession(id)
  })

  ipcMain.handle('db:session:restore', (_event, id: string) => {
    return getDatabase().restoreSession(id)
  })

  ipcMain.handle('db:session:getByConnection', (_event, connectionId: string) => {
    return getDatabase().getSessionsByConnection(connectionId)
  })

  ipcMain.handle('db:session:getActiveByConnection', (_event, connectionId: string) => {
    return getDatabase().getActiveSessionsByConnection(connectionId)
  })

  ipcMain.handle('db:session:search', (_event, options: SessionSearchOptions) => {
    return getDatabase().searchSessions(options)
  })

  ipcMain.handle('db:session:getDraft', (_event, sessionId: string) => {
    return getDatabase().getSessionDraft(sessionId)
  })

  ipcMain.handle('db:session:updateDraft', (_event, sessionId: string, draft: string | null) => {
    getDatabase().updateSessionDraft(sessionId, draft)
  })

  ipcMain.handle('db:sessionMessage:list', (_event, sessionId: string) => {
    return getDatabase().getSessionMessages(sessionId)
  })

  ipcMain.handle('db:sessionActivity:list', (_event, sessionId: string) => {
    return getDatabase().getSessionActivities(sessionId)
  })

  // Spaces
  ipcMain.handle('db:space:list', () => {
    return getDatabase().listSpaces()
  })

  ipcMain.handle('db:space:create', (_event, data: SpaceCreate) => {
    return getDatabase().createSpace(data)
  })

  ipcMain.handle('db:space:update', (_event, id: string, data: SpaceUpdate) => {
    return getDatabase().updateSpace(id, data)
  })

  ipcMain.handle('db:space:delete', (_event, id: string) => {
    return getDatabase().deleteSpace(id)
  })

  ipcMain.handle('db:space:assignProject', (_event, projectId: string, spaceId: string) => {
    getDatabase().assignProjectToSpace(projectId, spaceId)
    return true
  })

  ipcMain.handle('db:space:removeProject', (_event, projectId: string, spaceId: string) => {
    getDatabase().removeProjectFromSpace(projectId, spaceId)
    return true
  })

  ipcMain.handle('db:space:getProjectIds', (_event, spaceId: string) => {
    return getDatabase().getProjectIdsForSpace(spaceId)
  })

  ipcMain.handle('db:space:getAllAssignments', () => {
    return getDatabase().getAllProjectSpaceAssignments()
  })

  ipcMain.handle('db:space:reorder', (_event, orderedIds: string[]) => {
    getDatabase().reorderSpaces(orderedIds)
    return true
  })

  // Utility
  ipcMain.handle('db:schemaVersion', () => {
    return getDatabase().getSchemaVersion()
  })

  ipcMain.handle('db:tableExists', (_event, tableName: string) => {
    return getDatabase().tableExists(tableName)
  })

  ipcMain.handle('db:getIndexes', () => {
    return getDatabase().getIndexes()
  })
}
