import { afterEach, describe, expect, it } from 'bun:test'
import { mkdtemp, mkdir } from 'node:fs/promises'
import { join } from 'node:path'
import { tmpdir } from 'node:os'
import { resetConfigure } from './hooks.js'
import {
  buildGitCredentialEnv,
  prepareForAgent,
  readGitCredentials,
  redactUrlCredentials,
  resolveGitWorkDir,
  withHttpsCredentials,
} from './workspace.js'

const ENV_KEYS = [
  'WS_GIT_REPO_URL',
  'WS_GIT_WORK_DIR',
  'WS_GIT_USERNAME',
  'WS_GIT_PASSWORD',
] as const

function clearGitEnv(): void {
  for (const key of ENV_KEYS) {
    delete process.env[key]
  }
}

function saveGitEnv(): Record<string, string | undefined> {
  const saved: Record<string, string | undefined> = {}
  for (const key of ENV_KEYS) {
    saved[key] = process.env[key]
  }
  return saved
}

function restoreGitEnv(saved: Record<string, string | undefined>): void {
  for (const key of ENV_KEYS) {
    const value = saved[key]
    if (value === undefined) {
      delete process.env[key]
    } else {
      process.env[key] = value
    }
  }
}

describe('git-tool workspace helpers', () => {
  let savedEnv: Record<string, string | undefined> = {}

  afterEach(() => {
    restoreGitEnv(savedEnv)
    resetConfigure()
  })

  it('resolveGitWorkDir 未设置时默认 workspace/repo', () => {
    savedEnv = saveGitEnv()
    clearGitEnv()
    expect(resolveGitWorkDir('/tmp/agent-runtime/dev')).toBe(
      '/tmp/agent-runtime/dev/workspace/repo',
    )
  })

  it('resolveGitWorkDir 支持相对与绝对路径', () => {
    savedEnv = saveGitEnv()
    clearGitEnv()
    process.env.WS_GIT_WORK_DIR = 'checkout'
    expect(resolveGitWorkDir('/tmp/agent-runtime/dev')).toBe(
      '/tmp/agent-runtime/dev/workspace/checkout',
    )
    process.env.WS_GIT_WORK_DIR = '/data/repo'
    expect(resolveGitWorkDir('/tmp/agent-runtime/dev')).toBe('/data/repo')
  })

  it('readGitCredentials 均未设置返回 null', () => {
    savedEnv = saveGitEnv()
    clearGitEnv()
    expect(readGitCredentials()).toBe(null)
  })

  it('readGitCredentials 仅设置其一抛错', () => {
    savedEnv = saveGitEnv()
    clearGitEnv()
    process.env.WS_GIT_USERNAME = 'user'
    expect(() => readGitCredentials()).toThrow(
      'WS_GIT_USERNAME 与 WS_GIT_PASSWORD 必须成对设置',
    )
  })

  it('withHttpsCredentials 注入 HTTPS 凭据', () => {
    const url = withHttpsCredentials('https://git.example.com/a/b.git', {
      username: 'bot',
      password: 'secret',
    })
    expect(url).toContain('bot')
    expect(url).toContain('secret')
    expect(
      withHttpsCredentials('git@github.com:org/repo.git', {
        username: 'bot',
        password: 'secret',
      }),
    ).toBe('git@github.com:org/repo.git')
  })

  it('buildGitCredentialEnv 含 inline credential.helper', () => {
    const env = buildGitCredentialEnv({ username: 'u', password: 'p' })
    expect(env.GIT_TERMINAL_PROMPT).toBe('0')
    expect(env.GIT_CONFIG_COUNT).toBe('1')
    expect(env.GIT_CONFIG_VALUE_0).toContain('username=u')
    expect(env.GIT_CONFIG_VALUE_0).toContain('password=p')
  })

  it('redactUrlCredentials 脱敏 http(s) 凭据', () => {
    expect(
      redactUrlCredentials('https://user:token@git.example.com/r.git'),
    ).toBe('https://***:***@git.example.com/r.git')
  })
})

describe('prepareForAgent', () => {
  let savedEnv: Record<string, string | undefined> = {}

  afterEach(() => {
    restoreGitEnv(savedEnv)
    resetConfigure()
  })

  it('无 URL 且默认 workspace/repo 非 git 目录时返回 skipped', async () => {
    savedEnv = saveGitEnv()
    clearGitEnv()
    const operWorkspaceDir = await mkdtemp(join(tmpdir(), 'ws-git-missing-'))
    await expect(prepareForAgent({ operWorkspaceDir })).resolves.toBe('skipped')
  })

  it('WS_GIT_WORK_DIR 非 git 目录且无 URL 时返回 skipped', async () => {
    savedEnv = saveGitEnv()
    clearGitEnv()
    const operWorkspaceDir = await mkdtemp(join(tmpdir(), 'ws-git-notrepo-'))
    const notRepo = join(operWorkspaceDir, 'workspace', 'not-git')
    await mkdir(notRepo, { recursive: true })
    process.env.WS_GIT_WORK_DIR = 'not-git'
    await expect(prepareForAgent({ operWorkspaceDir })).resolves.toBe('skipped')
  })
})
