import type { YamlStore } from '../store/store'
import { mkdtemp, rm } from 'node:fs/promises'
import { tmpdir } from 'node:os'
import { join } from 'node:path'
import { afterEach, beforeEach, describe, expect, it } from 'vitest'
import { isBaseError } from '../errors/base'
import { ErrorCode } from '../errors/codes'
import { ENV_CONFIG_DIR } from '../store/dir'
import { getConfigurationStore } from '../store/manager'
import { loadConfig } from './config-loader'

describe('loadConfig', () => {
  let dir: string
  let prevConfigDir: string | undefined

  beforeEach(async () => {
    dir = await mkdtemp(join(tmpdir(), 'difyctl-cfg-'))
    prevConfigDir = process.env[ENV_CONFIG_DIR]
    process.env[ENV_CONFIG_DIR] = dir
  })

  afterEach(async () => {
    if (prevConfigDir === undefined)
      delete process.env[ENV_CONFIG_DIR]
    else
      process.env[ENV_CONFIG_DIR] = prevConfigDir
    await rm(dir, { recursive: true, force: true })
  })

  it('returns found:false when config is missing', () => {
    const r = loadConfig(getConfigurationStore())
    expect(r.found).toBe(false)
  })

  it('parses a minimal valid config', () => {
    getConfigurationStore().setTyped({ schema_version: 1 })
    const r = loadConfig(getConfigurationStore())
    expect(r.found).toBe(true)
    if (r.found)
      expect(r.config.schema_version).toBe(1)
  })

  it('parses defaults + state', () => {
    getConfigurationStore().setTyped({
      schema_version: 1,
      defaults: { format: 'json', limit: 100 },
      state: { current_app: 'app-1' },
    })
    const r = loadConfig(getConfigurationStore())
    expect(r.found).toBe(true)
    if (r.found) {
      expect(r.config.defaults.format).toBe('json')
      expect(r.config.defaults.limit).toBe(100)
      expect(r.config.state.current_app).toBe('app-1')
    }
  })

  it('throws BaseError(config_schema_unsupported) when the store fails to parse the file', () => {
    // Simulate a corrupt on-disk file via a fake store; loadConfig must wrap
    // the underlying error as ConfigSchemaUnsupported.
    const throwingStore = {
      getTyped: () => { throw new Error('YAML parse failure') },
    } as unknown as YamlStore
    let caught: unknown
    try {
      loadConfig(throwingStore)
    }
    catch (err) { caught = err }
    expect(isBaseError(caught)).toBe(true)
    if (isBaseError(caught)) {
      expect(caught.code).toBe(ErrorCode.ConfigSchemaUnsupported)
      expect(caught.hint).toMatch(/not valid YAML/)
    }
  })

  it('throws BaseError(config_schema_unsupported) when zod validation fails', () => {
    getConfigurationStore().setTyped({ defaults: { limit: 9999 } })
    let caught: unknown
    try {
      loadConfig(getConfigurationStore())
    }
    catch (err) { caught = err }
    expect(isBaseError(caught)).toBe(true)
    if (isBaseError(caught))
      expect(caught.code).toBe(ErrorCode.ConfigSchemaUnsupported)
  })

  it('throws BaseError(config_schema_unsupported) when schema_version > 1 (forward-refuse)', () => {
    getConfigurationStore().setTyped({ schema_version: 2 })
    let caught: unknown
    try {
      loadConfig(getConfigurationStore())
    }
    catch (err) { caught = err }
    expect(isBaseError(caught)).toBe(true)
    if (isBaseError(caught)) {
      expect(caught.code).toBe(ErrorCode.ConfigSchemaUnsupported)
      expect(caught.message).toMatch(/schema_version=2/)
      expect(caught.hint).toMatch(/upgrade difyctl/)
    }
  })
})
