import { mkdir } from 'node:fs/promises'
import { readConfig } from '../core/config.ts'
import { logger } from '../core/logger.ts'
import { DAEMON_PORT, paths } from '../core/paths.ts'
import { pricingCache } from './api/pricing.ts'
import { thomasCache } from './api/thomas.ts'
import { toolsCache } from './api/tools.ts'
import { startPricingRefreshLoop } from './cost/refresh-schedule.ts'
import { startSessionCorrelatorLoop } from './fleet/session-correlator.ts'
import { startMaintenanceLoop } from './maintenance.ts'
import { startServer } from './server.ts'
import { backfillOutcomes } from './store/backfill-outcomes.ts'
import { getRawDb } from './store/db.ts'
import { startUpdateCheckLoop } from './update/schedule.ts'

export type DaemonOptions = {
  port?: number
}

export async function startDaemon(opts: DaemonOptions = {}): Promise<void> {
  await ensureDirs()
  const port = opts.port ?? DAEMON_PORT
  await startServer({ port })
  logger.info(`OpenThomas daemon listening on http://localhost:${port}`)
  void startMaintenanceLoop()
  startUpdateCheckLoop()
  const cfg = await readConfig()
  if (cfg.autoRefreshPricing) startPricingRefreshLoop()
  if (cfg.correlateSessions) startSessionCorrelatorLoop()

  // Background keep-warm for the three heavy aggregation endpoints. Each
  // loop is idle-aware: if no client has hit the endpoint in the last 30
  // minutes, the refresh is skipped. So the daemon idles overnight
  // instead of running the scan constantly.
  thomasCache.startKeepWarm(30_000)
  toolsCache.startKeepWarm(30_000)
  pricingCache.startKeepWarm(30_000)
  logger.info('keep-warm: /api/thomas + /api/tools + /api/pricing every 30s (idle-aware)')

  // One-time backfill of outcomes + tool_uses from existing actions.
  // Runs async after the server is up so the dashboard works
  // immediately while history populates in the background.
  void (async () => {
    try {
      const raw = await getRawDb()
      await backfillOutcomes(raw)
      // After backfill, invalidate caches so the next query sees the
      // fully-populated tables.
      thomasCache.invalidate()
      toolsCache.invalidate()
    } catch (err) {
      logger.warn(`backfill-outcomes failed: ${(err as Error).message}`)
    }
  })()
}

async function ensureDirs(): Promise<void> {
  await mkdir(paths.home, { recursive: true })
  await mkdir(paths.wire.dir, { recursive: true })
  await mkdir(paths.wire.traces, { recursive: true })
  await mkdir(paths.backups.dir, { recursive: true })
  await mkdir(paths.logs.dir, { recursive: true })
}
