/**
 * Shared configuration loading logic for DimCode CLI.
 *
 * Used by both the TUI mode and ACP Server mode to read/write user settings.
 */

import {
  resolveDimcodeConfigDir,
  resolveDimcodeUserDir,
} from './storage-paths'

export { APP_DIR_NAME, CONFIG_DIR_NAME, STATE_DIR_NAME } from './storage-paths'

type RuntimeGlobals = typeof globalThis & {
  process?: NodeJS.Process
}

export type McpServerSettings
  = | McpHttpSettings
    | McpSseSettings
    | McpStdioSettings

export type McpHttpSettings = Readonly<{
  id: string
  name: string
  transport: 'http'
  url: string
  auth?: {
    type: 'bearer'
    token: string
  }
  headers?: Record<string, string>
  requestTimeoutMs?: number
  enabled?: boolean
}>

export type McpSseSettings = Readonly<{
  id: string
  name: string
  transport: 'sse'
  url: string
  auth?: {
    type: 'bearer'
    token: string
  }
  headers?: Record<string, string>
  requestTimeoutMs?: number
  enabled?: boolean
}>

export type McpStdioSettings = Readonly<{
  id: string
  name: string
  transport: 'stdio'
  command: string
  args: readonly string[]
  env?: Record<string, string>
  cwd?: string
  autoRestart?: boolean
  requestTimeoutMs?: number
  restartDelayMs?: number
  maxRestarts?: number
  restartWindowMs?: number
  enabled?: boolean
}>

export type DimcodeUserSettings = Readonly<{
  model?: string
  authMethod?: 'oauth' | 'api'
  contextWindow?: number
  temperature?: number
  interleavedThinking?: boolean
  baseUrl?: string
  apiKey?: string
  toolApprovals?: 'auto' | 'normal' | 'strict'
  locale?: string
  mcpServers?: readonly McpServerSettings[]
}>

export type DimcodeUserCacheV1 = Readonly<{
  version: 1
  updatedAt: number
  settings?: DimcodeUserSettings
  lastSessionId?: string
  sessions?: Readonly<
    Record<
      string,
      Readonly<{
        updatedAt: number
        cwd?: string
        focusFiles?: readonly string[]
        title?: string
        summary?: string
        messages?: unknown[]
        revertedMessages?: unknown[]
        usage?: unknown
      }>
    >
  >
}>

export function normalizeStr(v: unknown): string | undefined {
  const s = String(v ?? '').trim()
  return s || undefined
}

export function normalizeNum(v: unknown): number | undefined {
  if (typeof v === 'number' && Number.isFinite(v))
    return v
  const s = String(v ?? '').trim()
  if (!s)
    return undefined
  const n = Number(s)
  return Number.isFinite(n) ? n : undefined
}

function runtimeGlobals(): RuntimeGlobals {
  return globalThis as RuntimeGlobals
}

function runtimeEnv(): Record<string, string | undefined> {
  return runtimeGlobals().process?.env ?? {}
}

function isRecord(value: unknown): value is Record<string, unknown> {
  return value != null && typeof value === 'object' && !Array.isArray(value)
}

function isDimcodeUserCacheV1(value: unknown): value is DimcodeUserCacheV1 {
  return isRecord(value) && value.version === 1
}

export async function getDimcodeUserDir(): Promise<string> {
  return resolveDimcodeUserDir(runtimeEnv())
}

export async function loadDimcodeUserCache(): Promise<{
  dir: string
  filePath: string
  cache: DimcodeUserCacheV1
}> {
  const dir = await getDimcodeUserDir()
  const [{ readFile }, path] = await Promise.all([
    import('node:fs/promises'),
    import('node:path'),
  ])
  const filePath = path.join(dir, 'cache.json')
  try {
    const raw = await readFile(filePath, 'utf8')
    const parsed = JSON.parse(raw)
    if (isDimcodeUserCacheV1(parsed))
      return { dir, filePath, cache: parsed }
  }
  catch {
    // ignore
  }
  return { dir, filePath, cache: { version: 1, updatedAt: 0 } as const }
}

export async function getDimcodeConfigDir(): Promise<string> {
  return resolveDimcodeConfigDir(runtimeEnv())
}

export async function saveDimcodeUserCache(
  filePath: string,
  cache: DimcodeUserCacheV1,
): Promise<void> {
  const [{ mkdir, writeFile, rename, chmod }, path] = await Promise.all([
    import('node:fs/promises'),
    import('node:path'),
  ])
  const dir = path.dirname(filePath)
  await mkdir(dir, { recursive: true })
  const tmp = `${filePath}.tmp`
  const data = `${JSON.stringify(cache, null, 2)}\n`
  await writeFile(tmp, data, { encoding: 'utf8', mode: 0o600 })
  await rename(tmp, filePath)
  try {
    await chmod(filePath, 0o600)
  }
  catch {
    // ignore
  }
}
