import { afterEach, describe, expect, it, vi } from 'vitest'

const {
  ensurePrefixedEnvValueMock,
  readPrefixedEnvMock,
  readPrefixedEnvFlagMock,
  setPrefixedEnvValueMock,
  detectTerminalColorCapabilityMock,
  watchMock,
  parseCliArgsMock,
  createDimSdkShellPropsMock,
  runTerminalUiMock,
  createDimSdkRouterMock,
  saveTerminalTitleMock,
  setTerminalTitleMock,
  restoreTerminalTitleMock,
  setModeMock,
  originalOnStoreCreatedMock,
  applyThemeUpdateMock,
} = vi.hoisted(() => ({
  ensurePrefixedEnvValueMock: vi.fn(
    (env: Record<string, string | undefined>, key: string, value: string) => {
      const fullKey = `DIMCODE_${key}`
      if (!env[fullKey])
        env[fullKey] = value
      return env[fullKey]
    },
  ),
  readPrefixedEnvMock: vi.fn(() => ''),
  readPrefixedEnvFlagMock: vi.fn(() => ''),
  setPrefixedEnvValueMock: vi.fn(
    (env: Record<string, string | undefined>, key: string, value: string) => {
      env[`DIMCODE_${key}`] = value
    },
  ),
  detectTerminalColorCapabilityMock: vi.fn(() => ({ level: 256 })),
  watchMock: vi.fn(
    (
      source: () => string,
      callback: (value: string) => void,
      options?: { immediate?: boolean },
    ) => {
      if (options?.immediate)
        callback(source())
      return vi.fn()
    },
  ),
  parseCliArgsMock: vi.fn(() => ({
    app: 'dim',
    cols: 80,
    rows: 24,
    sizeLocked: false,
    debug: false,
    approvals: undefined,
    initialRoute: 'home',
    altScreen: false,
    enableMouse: false,
    recordPath: null,
    replayPath: null,
    snapshotPath: null,
  })),
  createDimSdkShellPropsMock: vi.fn(),
  runTerminalUiMock: vi.fn(),
  createDimSdkRouterMock: vi.fn(() => ({ name: 'router' })),
  saveTerminalTitleMock: vi.fn(),
  setTerminalTitleMock: vi.fn(),
  restoreTerminalTitleMock: vi.fn(),
  setModeMock: vi.fn(),
  originalOnStoreCreatedMock: vi.fn(),
  applyThemeUpdateMock: vi.fn(),
}))

vi.mock('#cli/core/env', () => ({
  ensurePrefixedEnvValue: ensurePrefixedEnvValueMock,
  readPrefixedEnv: readPrefixedEnvMock,
  readPrefixedEnvFlag: readPrefixedEnvFlagMock,
  setPrefixedEnvValue: setPrefixedEnvValueMock,
}))

vi.mock('#cli/core/markdown', () => ({
  startMarkdownCacheCleanup: vi.fn(),
}))

vi.mock('#cli/core/observability/event-loop-lag', () => ({
  startEventLoopLagLogger: vi.fn(),
}))

vi.mock('#cli/core/observability/gc-log', () => ({
  startGcLogger: vi.fn(),
}))

vi.mock('#cli/core/observability/perf-log', () => ({
  isOneShotEnabled: vi.fn(() => false),
  isPerfEnabled: vi.fn(() => false),
  perfLog: vi.fn(),
}))

vi.mock('#cli/core/observability/trace-log', () => ({
  traceLog: vi.fn(),
}))

vi.mock('#cli/core/theme', () => ({
  resolveInitialThemeMode: vi.fn(() => 'dark'),
}))

vi.mock('@simon_he/vue-tui', () => ({
  detectTerminalColorCapability: detectTerminalColorCapabilityMock,
}))

vi.mock('vue', () => ({
  watch: watchMock,
}))

vi.mock('../src/dimsdk/cli/args.ts', () => ({
  getHelpText: vi.fn(() => 'help'),
  isHelpRequested: vi.fn(() => false),
  parseCliArgs: parseCliArgsMock,
}))

vi.mock('../src/dimsdk/cli/binary-upgrade.ts', () => ({
  isSelfContainedBinary: vi.fn(() => false),
  maybeRelaunchToUpdatedBinary: vi.fn(async () => false),
  runBinaryUpgradeCommand: vi.fn(),
}))

vi.mock('../src/dimsdk/cli/exec.ts', () => ({
  runExec: vi.fn(),
}))

vi.mock('../src/dimsdk/cli/dimsdk-app.ts', () => ({
  createDimSdkShellProps: createDimSdkShellPropsMock,
}))

vi.mock('../src/dimsdk/cli/runtime.ts', () => ({
  queueUpgradeToast: vi.fn(),
  requestFatalExit: vi.fn(),
  setupCrashHandlers: vi.fn(),
  withTimeout: vi.fn(),
}))

vi.mock('../src/dimsdk/cli/terminal.ts', () => ({
  runTerminalUi: runTerminalUiMock,
}))

vi.mock('../src/dimsdk/cli/top-level.ts', () => ({
  resolveTopLevelSubcommand: vi.fn(() => ({ kind: 'none', argv: [] })),
}))

vi.mock('../src/dimsdk/cli/upgrade.ts', () => ({
  checkUpgrade: vi.fn(async () => null),
  getNpmPackageOverride: vi.fn(() => null),
}))

vi.mock('../src/dimsdk/cli/upgrade-check.ts', () => ({
  runNpmUpgradeCommand: vi.fn(),
}))

vi.mock('../src/dimsdk/cli/upgrade-loop.ts', () => ({
  createUpgradeMessageReporter: vi.fn(() => vi.fn()),
  resolveBackgroundUpgradeCheckIntervalMs: vi.fn(() => 60_000),
  startBackgroundUpgradeChecks: vi.fn(() => vi.fn()),
}))

vi.mock('../src/dimsdk/cli/version-info.ts', () => ({
  printCliVersionInfo: vi.fn(),
}))

vi.mock('../src/dimsdk/commands/auth.ts', () => ({
  runAuthCommand: vi.fn(),
}))

vi.mock('../src/dimsdk/core/feature-flags.ts', () => ({
  isNextApiAuthEnabled: vi.fn(() => false),
}))

vi.mock('../src/dimsdk/index.ts', () => ({
  createDimSdkRouter: createDimSdkRouterMock,
  DimSdkShell: { name: 'DimSdkShell' },
}))

vi.mock('../src/dimsdk/ui/terminal-title.ts', () => ({
  restoreTerminalTitle: restoreTerminalTitleMock,
  saveTerminalTitle: saveTerminalTitleMock,
  setTerminalTitle: setTerminalTitleMock,
}))

vi.mock('../src/dimsdk/ui/theme/index.ts', () => ({
  createUiThemeSwitcher: vi.fn(() => ({
    context: {
      token: vi.fn(() => ({ bg: 'black' })),
      style: vi.fn(() => ({ fg: 'whiteBright', bg: 'black' })),
      palette: { black: '#000000' },
    },
    setMode: setModeMock,
    getMode: vi.fn(() => 'dark'),
  })),
  DimSdkUiThemeKey: Symbol('DimSdkUiThemeKey'),
}))

const realProcess = globalThis.process

function setProcessEnv(env: Record<string, string | undefined>): void {
  Object.defineProperty(globalThis, 'process', {
    configurable: true,
    value: {
      ...realProcess,
      argv: ['/usr/local/bin/node', 'dim'],
      cwd: () => '/repo',
      env,
      platform: 'darwin',
      stdout: {
        ...realProcess.stdout,
        isTTY: true,
      },
    },
  })
}

afterEach(() => {
  Object.defineProperty(globalThis, 'process', {
    configurable: true,
    value: realProcess,
  })
  vi.clearAllMocks()
  readPrefixedEnvMock.mockReturnValue('')
  readPrefixedEnvFlagMock.mockReturnValue('')
  parseCliArgsMock.mockReturnValue({
    app: 'dim',
    cols: 80,
    rows: 24,
    sizeLocked: false,
    debug: false,
    approvals: undefined,
    initialRoute: 'home',
    altScreen: false,
    enableMouse: false,
    recordPath: null,
    replayPath: null,
    snapshotPath: null,
  })
})

describe('runCli', () => {
  it('uses the typed runtime process bridge and preserves wrapped dim shell props', async () => {
    vi.resetModules()
    const env: Record<string, string | undefined> = {
      DIMCODE_DEBUG: '0',
    }
    setProcessEnv(env)

    createDimSdkShellPropsMock.mockResolvedValue({
      toolRunner: vi.fn(),
      context: { system: 'system', cwd: '/repo', env },
      agent: {},
      onStoreCreated: originalOnStoreCreatedMock,
    })

    runTerminalUiMock.mockImplementation(async (opts: {
      props?: {
        onStoreCreated?: (store: {
          state: { ui: { theme: { mode: string } } }
        }) => void
      }
      onThemeReady?: (update: (next: unknown) => void) => void
    }) => {
      opts.onThemeReady?.(applyThemeUpdateMock)
      opts.props?.onStoreCreated?.({
        state: {
          ui: {
            theme: { mode: 'light' },
          },
        },
      })
    })

    const { runCli } = await import('../src/dimsdk/cli.ts')
    await runCli([])

    expect(createDimSdkShellPropsMock).toHaveBeenCalledWith({
      cwd: '/repo',
      env,
    })
    expect(detectTerminalColorCapabilityMock).toHaveBeenCalledWith({
      env,
      isTTY: true,
      platform: 'darwin',
    })
    expect(originalOnStoreCreatedMock).toHaveBeenCalledTimes(1)
    expect(setModeMock).toHaveBeenCalledWith('light')
    expect(applyThemeUpdateMock).toHaveBeenCalledTimes(1)
    expect(saveTerminalTitleMock).toHaveBeenCalledWith({
      stdout: expect.anything(),
      env,
    })
    expect(restoreTerminalTitleMock).toHaveBeenCalledWith({
      stdout: expect.anything(),
      env,
    })
  })
})
