import type { GoatChainMessageType } from './message-types'
import { readPrefixedEnv } from './env'
import { GoatChainMessageTypes } from './message-types'

export type AnsiColorName
  = | 'black'
    | 'red'
    | 'green'
    | 'yellow'
    | 'blue'
    | 'magenta'
    | 'cyan'
    | 'white'
    | 'blackBright'
    | 'redBright'
    | 'greenBright'
    | 'yellowBright'
    | 'blueBright'
    | 'magentaBright'
    | 'cyanBright'
    | 'whiteBright'

export const AnsiColorNames = [
  'black',
  'red',
  'green',
  'yellow',
  'blue',
  'magenta',
  'cyan',
  'white',
  'blackBright',
  'redBright',
  'greenBright',
  'yellowBright',
  'blueBright',
  'magentaBright',
  'cyanBright',
  'whiteBright',
] as const

/** Backward-compatible alias — every ThemeId maps to a ThemeModeId. */
export type ThemeModeId = 'dark' | 'light'

/**
 * A concrete theme identifier. Built-in IDs are `'monokai-dark'` and `'monokai-light'`.
 * Custom themes can be registered at runtime via `registerThemeMessageColors`.
 */
export type ThemeId = string

export type MessageTypeColors = Readonly<{
  fg?: AnsiColorName
  bg?: AnsiColorName
}>

export type ThemeState = Readonly<{
  mode: ThemeId
}>

/**
 * Metadata stored alongside every registered theme's message-type colors.
 */
export type ThemeRegistryEntry = Readonly<{
  /** Human-readable label shown in the theme picker. */
  label: string
  /** The underlying color mode (controls shiki highlighting, etc.). */
  colorMode: ThemeModeId
  /** Per-message-type colors. */
  messageColors: Record<GoatChainMessageType, MessageTypeColors>
}>

function makeBase(
  fg: AnsiColorName,
  bg: AnsiColorName,
): Record<GoatChainMessageType, MessageTypeColors> {
  const out: Record<string, MessageTypeColors> = {}
  for (const t of GoatChainMessageTypes) out[t] = { fg, bg }
  return out as Record<GoatChainMessageType, MessageTypeColors>
}

// ---------------------------------------------------------------------------
// Theme registry
// ---------------------------------------------------------------------------

const themeRegistry = new Map<ThemeId, ThemeRegistryEntry>()

/** Built-in dark message colors (Monokai Dark). */
export const DARK_MESSAGE_COLORS: Record<GoatChainMessageType, MessageTypeColors>
  = Object.freeze({
    ...makeBase('white', 'black'),
    user: { fg: 'white', bg: 'blackBright' },
    assistant: { fg: 'white', bg: 'black' },
    tool: { fg: 'white', bg: 'black' },
    markdown: { fg: 'white', bg: 'black' },
    status: { fg: 'blueBright', bg: 'blackBright' },
    thinking: { fg: 'magentaBright', bg: 'black' },
    tool_call: { fg: 'yellowBright', bg: 'black' },
    tool_output: { fg: 'blueBright', bg: 'black' },
    tool_result: { fg: 'white', bg: 'black' },
    approve: { fg: 'yellowBright', bg: 'black' },
    todo: { fg: 'greenBright', bg: 'black' },
    plan: { fg: 'magentaBright', bg: 'black' },
    info: { fg: 'yellowBright', bg: 'black' },
  }) as Record<GoatChainMessageType, MessageTypeColors>

/** Built-in light message colors (Monokai Light). */
export const LIGHT_MESSAGE_COLORS: Record<GoatChainMessageType, MessageTypeColors>
  = Object.freeze({
    ...makeBase('black', 'white'),
    user: { fg: 'black', bg: 'blackBright' },
    assistant: { fg: 'black', bg: 'white' },
    tool: { fg: 'black', bg: 'white' },
    markdown: { fg: 'black', bg: 'white' },
    status: { fg: 'blue', bg: 'whiteBright' },
    thinking: { fg: 'magentaBright', bg: 'white' },
    tool_call: { fg: 'blue', bg: 'white' },
    tool_output: { fg: 'cyanBright', bg: 'white' },
    tool_result: { fg: 'black', bg: 'white' },
    approve: { fg: 'yellow', bg: 'white' },
    todo: { fg: 'green', bg: 'white' },
    plan: { fg: 'magenta', bg: 'white' },
    info: { fg: 'yellow', bg: 'white' },
  }) as Record<GoatChainMessageType, MessageTypeColors>

// Register the two built-in themes.
themeRegistry.set('monokai-dark', {
  label: 'Monokai Dark',
  colorMode: 'dark',
  messageColors: DARK_MESSAGE_COLORS,
})
themeRegistry.set('monokai-light', {
  label: 'Monokai Light',
  colorMode: 'light',
  messageColors: LIGHT_MESSAGE_COLORS,
})

/** Register (or overwrite) a theme's message-type colors. */
export function registerThemeMessageColors(
  id: ThemeId,
  entry: ThemeRegistryEntry,
): void {
  themeRegistry.set(id, entry)
}

/** Return a snapshot of all registered theme IDs. */
export function getRegisteredThemeIds(): ThemeId[] {
  return [...themeRegistry.keys()]
}

/** Look up a registry entry by theme ID. */
export function getThemeEntry(id: ThemeId): ThemeRegistryEntry | undefined {
  return themeRegistry.get(id)
}

/**
 * Backward-compatible: `ThemeModes` still works for existing code that indexes
 * by `'dark' | 'light'`.
 */
export const ThemeModes: Readonly<
  Record<ThemeModeId, Record<GoatChainMessageType, MessageTypeColors>>
> = Object.freeze({
  dark: DARK_MESSAGE_COLORS,
  light: LIGHT_MESSAGE_COLORS,
})

/**
 * Normalize a raw theme value to a known `ThemeId`.
 *
 * - Known registry IDs pass through.
 * - Legacy `'dark'` / `'light'` map to `'monokai-dark'` / `'monokai-light'`.
 * - Unknown values fall back to `'monokai-dark'`.
 */
export function normalizeThemeId(raw: unknown): ThemeId {
  const v = String(raw ?? '')
    .trim()
    .toLowerCase()
  if (themeRegistry.has(v))
    return v
  if (v === 'light')
    return 'monokai-light'
  if (v === 'dark')
    return 'monokai-dark'
  // Preserve non-empty IDs for late-registered themes (e.g. community themes)
  if (v)
    return v
  return 'monokai-dark'
}

/** Extract the underlying `ThemeModeId` (`'dark'`/`'light'`) from any theme ID. */
export function themeColorMode(id: ThemeId): ThemeModeId {
  return getThemeEntry(normalizeThemeId(id))?.colorMode ?? 'dark'
}

/**
 * Backward-compat helper. Normalizes arbitrary input to `'dark' | 'light'`.
 */
export function normalizeThemeMode(mode: unknown): ThemeModeId {
  const v = String(mode ?? '')
    .trim()
    .toLowerCase()
  if (v === 'light' || v === 'monokai-light')
    return 'light'
  if (v === 'dark' || v === 'monokai-dark')
    return 'dark'
  // Check registry for custom themes
  const entry = themeRegistry.get(v)
  if (entry)
    return entry.colorMode
  if (v === 'goatchain' || v === 'dimcode' || v === 'mono' || v === 'contrast')
    return 'dark'
  return 'dark'
}

export function detectSystemTheme(
  env?: Record<string, string | undefined>,
): ThemeModeId {
  try {
    const mm = (globalThis as any)?.matchMedia
    if (typeof mm === 'function')
      return mm('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'
  }
  catch {
    // ignore
  }

  const procEnv = (env ?? (globalThis as any)?.process?.env ?? {}) as Record<
    string,
    string | undefined
  >
  const colorfgbg = String(procEnv.COLORFGBG ?? '').trim()
  if (colorfgbg) {
    const parts = colorfgbg
      .split(/[;,]/)
      .map(p => p.trim())
      .filter(Boolean)
    const bgRaw = parts[parts.length - 1]
    const bg = Number.parseInt(bgRaw ?? '', 10)
    if (Number.isFinite(bg))
      return bg >= 7 ? 'light' : 'dark'
  }

  return 'dark'
}

export function resolveInitialThemeMode(
  env?: Record<string, string | undefined>,
): ThemeModeId {
  const pref = readPrefixedEnv(env, 'THEME')
  if (pref)
    return normalizeThemeMode(pref)
  return detectSystemTheme(env)
}

/** Resolve the initial ThemeId (returns a concrete registry key). */
export function resolveInitialThemeId(
  env?: Record<string, string | undefined>,
): ThemeId {
  const pref = readPrefixedEnv(env, 'THEME')
  if (pref)
    return normalizeThemeId(pref)
  const sysMode = detectSystemTheme(env)
  return sysMode === 'light' ? 'monokai-light' : 'monokai-dark'
}

export function resolveShikiTheme(mode: ThemeModeId | ThemeId | undefined): string {
  const cm = typeof mode === 'string' ? normalizeThemeMode(mode) : 'dark'
  return cm === 'light' ? 'github-light' : 'monokai'
}

export function resolveMessageTypeColors(
  theme: ThemeState,
  type: GoatChainMessageType,
): MessageTypeColors {
  const raw = (theme as any)?.mode ?? (theme as any)?.preset
  const id = normalizeThemeId(raw)
  const entry = getThemeEntry(id)
  if (entry) {
    const base = entry.messageColors[type] ?? entry.messageColors.assistant ?? { fg: 'white', bg: 'black' }
    return { ...base }
  }
  // Fallback for legacy
  const mode = normalizeThemeMode(raw)
  const preset = ThemeModes[mode] ?? ThemeModes.dark
  const base = preset[type] ?? preset.assistant ?? { fg: 'white', bg: 'black' }
  return { ...base }
}
