// tests/figma-env.test.ts
import { describe, it, expect, afterEach } from 'vitest'
import { mkdtempSync, mkdirSync, writeFileSync, rmSync } from 'node:fs'
import { tmpdir } from 'node:os'
import { join, resolve, dirname } from 'node:path'
import { fileURLToPath, pathToFileURL } from 'node:url'
import { execFileSync } from 'node:child_process'
import { loadDotEnv, getFigmaToken, requireFigmaToken } from '../scripts/lib/figma-env.mjs'

// `package.json` 是 type:module —— 显式派生，不依赖 vitest 注入 __dirname
const HERE = dirname(fileURLToPath(import.meta.url))

const dirs: string[] = []
function tmpWithEnv(contents: string | null): string {
  const d = mkdtempSync(join(tmpdir(), 'f98-'))
  dirs.push(d)
  if (contents !== null) writeFileSync(join(d, '.env'), contents)
  return d
}
afterEach(() => { while (dirs.length) rmSync(dirs.pop()!, { recursive: true, force: true }) })

describe('loadDotEnv', () => {
  it('reads keys from .env into the given env object', () => {
    const cwd = tmpWithEnv('FIGMA_TOKEN=figd_from_file\n')
    const env: Record<string, string> = {}
    loadDotEnv({ cwd, env })
    expect(env.FIGMA_TOKEN).toBe('figd_from_file')
  })

  it('never overwrites a key that already exists', () => {
    const cwd = tmpWithEnv('FIGMA_TOKEN=figd_from_file\n')
    const env: Record<string, string> = { FIGMA_TOKEN: 'figd_from_shell' }
    loadDotEnv({ cwd, env })
    expect(env.FIGMA_TOKEN).toBe('figd_from_shell')
  })

  it('is a silent no-op when .env does not exist', () => {
    const cwd = tmpWithEnv(null)
    const env: Record<string, string> = {}
    expect(() => loadDotEnv({ cwd, env })).not.toThrow()
    expect(Object.keys(env)).toHaveLength(0)
  })

  it('skips blank lines and comments, and keeps "=" inside values', () => {
    const cwd = tmpWithEnv('\n# a comment\nFIGMA_TOKEN=a=b=c\n')
    const env: Record<string, string> = {}
    loadDotEnv({ cwd, env })
    expect(env.FIGMA_TOKEN).toBe('a=b=c')
  })

  // review round 2 finding 2 — cwd isn't always the repo root (e.g. running from docs/).
  it('finds .env by walking up from a nested cwd to the nearest package.json/.git', () => {
    const root = mkdtempSync(join(tmpdir(), 'f98-'))
    dirs.push(root)
    writeFileSync(join(root, 'package.json'), '{}')
    writeFileSync(join(root, '.env'), 'FIGMA_TOKEN=figd_from_root\n')
    const nested = join(root, 'a', 'b')
    mkdirSync(nested, { recursive: true })
    const env: Record<string, string> = {}
    loadDotEnv({ cwd: nested, env })
    expect(env.FIGMA_TOKEN).toBe('figd_from_root')
  })

  // review round 2 finding 3 — three common .env idioms the hand-written parser used to mangle.
  it('strips a matched pair of surrounding double quotes from the value', () => {
    const cwd = tmpWithEnv('FIGMA_TOKEN="figd_quoted"\n')
    const env: Record<string, string> = {}
    loadDotEnv({ cwd, env })
    expect(env.FIGMA_TOKEN).toBe('figd_quoted')
  })

  it('strips a matched pair of surrounding single quotes from the value', () => {
    const cwd = tmpWithEnv("FIGMA_TOKEN='figd_quoted'\n")
    const env: Record<string, string> = {}
    loadDotEnv({ cwd, env })
    expect(env.FIGMA_TOKEN).toBe('figd_quoted')
  })

  it('strips a leading "export " from the key', () => {
    const cwd = tmpWithEnv('export FIGMA_TOKEN=figd_exported\n')
    const env: Record<string, string> = {}
    loadDotEnv({ cwd, env })
    expect(env.FIGMA_TOKEN).toBe('figd_exported')
    expect(env['export FIGMA_TOKEN']).toBeUndefined()
  })

  it('strips an unquoted trailing "# comment"', () => {
    const cwd = tmpWithEnv('FIGMA_TOKEN=figd_real # comment\n')
    const env: Record<string, string> = {}
    loadDotEnv({ cwd, env })
    expect(env.FIGMA_TOKEN).toBe('figd_real')
  })

  it('preserves a "#" inside a quoted value (not treated as a comment)', () => {
    const cwd = tmpWithEnv('FIGMA_TOKEN="figd_has_#_inside"\n')
    const env: Record<string, string> = {}
    loadDotEnv({ cwd, env })
    expect(env.FIGMA_TOKEN).toBe('figd_has_#_inside')
  })

  // review round 3 (coordinator) — residual case: a quoted value followed by a trailing
  // comment used to keep its quotes, because quote-stripping bailed on `endsWith(quote)`
  // (the value ends in "comment", not in the closing quote) and comment-stripping then ran
  // on the still-quoted string, leaving `"figd_abc"` (literal quotes) instead of `figd_abc`.
  it('strips both the surrounding quotes and a trailing comment on a quoted value', () => {
    const cwd = tmpWithEnv('FIGMA_TOKEN="figd_abc" # my token\n')
    const env: Record<string, string> = {}
    loadDotEnv({ cwd, env })
    expect(env.FIGMA_TOKEN).toBe('figd_abc')
  })
})

describe('getFigmaToken', () => {
  it('takes the canonical name', () => {
    const cwd = tmpWithEnv(null)
    expect(getFigmaToken({ cwd, env: { FIGMA_PERSONAL_ACCESS_TOKEN: 'figd_canon' } })).toBe('figd_canon')
  })

  it('falls back to the alias when only the alias is set', () => {
    const cwd = tmpWithEnv(null)
    expect(getFigmaToken({ cwd, env: { FIGMA_TOKEN: 'figd_alias' } })).toBe('figd_alias')
  })

  it('prefers the canonical name when both are set', () => {
    const cwd = tmpWithEnv(null)
    const env = { FIGMA_PERSONAL_ACCESS_TOKEN: 'figd_canon', FIGMA_TOKEN: 'figd_alias' }
    expect(getFigmaToken({ cwd, env })).toBe('figd_canon')
  })

  it('resolves from .env when the process env has neither', () => {
    const cwd = tmpWithEnv('FIGMA_TOKEN=figd_from_file\n')
    expect(getFigmaToken({ cwd, env: {} })).toBe('figd_from_file')
  })

  it('treats the .env.example placeholder as absent (both names)', () => {
    const cwd = tmpWithEnv(null)
    expect(getFigmaToken({ cwd, env: { FIGMA_PERSONAL_ACCESS_TOKEN: 'your_figma_personal_access_token_here' } })).toBeUndefined()
    expect(getFigmaToken({ cwd, env: { FIGMA_TOKEN: 'your_figma_token_here' } })).toBeUndefined()
  })

  it('returns undefined instead of exiting when nothing is configured', () => {
    const cwd = tmpWithEnv(null)
    expect(getFigmaToken({ cwd, env: {} })).toBeUndefined()
  })
})

describe('requireFigmaToken', () => {
  it('returns the token without exiting when configured', () => {
    const cwd = tmpWithEnv(null)
    expect(requireFigmaToken({ cwd, env: { FIGMA_TOKEN: 'figd_alias' } })).toBe('figd_alias')
  })

  it('exits 2 and names the canonical variable when nothing is configured', () => {
    const cwd = tmpWithEnv(null)
    const mod = resolve(HERE, '../scripts/lib/figma-env.mjs')
    const probe = join(cwd, 'probe.mjs')
    // import 说明符必须是 file:// URL——Windows 绝对路径（`D:\...`）当字面量喂给 `import`
    // 会被当成 URL scheme `d:` 解析，抛 ERR_UNSUPPORTED_ESM_URL_SCHEME（POSIX 路径因为
    // 以 `/` 开头，凑巧被当成相对 file: URL 解析出来，才让这条路径在 POSIX 上误打误撞可用）。
    writeFileSync(probe, `import { requireFigmaToken } from ${JSON.stringify(pathToFileURL(mod).href)}\nrequireFigmaToken()\n`)
    let code = 0
    let stderr = ''
    try {
      execFileSync(process.execPath, [probe], { cwd, env: { PATH: process.env.PATH ?? '' }, encoding: 'utf8' })
    } catch (e: any) {
      code = e.status
      stderr = String(e.stderr)
    }
    expect(code).toBe(2)
    expect(stderr).toContain('FIGMA_PERSONAL_ACCESS_TOKEN')
    expect(stderr).toContain('.env')
  })
})
