import { describe, it, expect } from 'vitest'
import { execFileSync } from 'node:child_process'
import { readFileSync } from 'node:fs'
import { resolve, dirname } from 'node:path'
import { fileURLToPath } from 'node:url'
import { markerTracked, FAILURE_MESSAGE } from '../scripts/audit-deploy-marker.mjs'

const __dirname = dirname(fileURLToPath(import.meta.url))

// INFRA-F123 第 7 条 —— `.deploy-hook-no-build` 是 docs 站 deploy 链的单点防线，立项时全仓零闸。
describe('audit-deploy-marker', () => {
  it('真 runner：marker 当前被 git 跟踪', () => {
    expect(markerTracked()).toBe(true)
  })

  it('注入 runner 抛错（= 未被跟踪）时判 false —— 判据非恒真', () => {
    expect(markerTracked(() => { throw new Error('not tracked') })).toBe(false)
  })

  it('阴性对照：同一条 git 命令查一个不存在的路径，确实会抛 —— 证明判据不是空过', () => {
    expect(() => execFileSync(
      'git', ['ls-files', '--error-unmatch', '.deploy-hook-no-build-does-not-exist'], { stdio: 'pipe' },
    )).toThrow()
  })

  it('判的是「被 git 跟踪」而不是「磁盘上有」—— 故障模式是 git rm 后文件仍留在磁盘', () => {
    // 契约断言：实现必须走 git ls-files，不许退化成 existsSync（后者恰好漏掉 untrack 那一种）。
    // ⚠️ 断言只看**代码行**：头注释里逐字解释了「为什么不用 existsSync」，全文匹配会被自己的
    //    说明文字污染（memory fault-probe-name-must-be-absent-from-repo 的同一形态）。
    const code = readFileSync(resolve(__dirname, '..', 'scripts', 'audit-deploy-marker.mjs'), 'utf8')
      .split('\n').filter(l => !l.trim().startsWith('//')).join('\n')
    expect(code).toContain('ls-files')
    expect(code).not.toContain('existsSync')
  })

  it('失败信息说清后果，不只是说「文件没了」', () => {
    expect(FAILURE_MESSAGE).toContain('静默回滚')
    expect(FAILURE_MESSAGE).toContain('find_buildable_dirs')
  })
})
