/**
 * cold-import 上传解压 — extractWhitelisted 白名单 + zip-slip 防护
 *
 * 覆盖:
 *   - 白名单过滤:zip 里白名单外的文件(c.csv)不提取
 *   - 子目录条目按 basename 落平(sub/nested.csv → nested.csv,若在白名单)
 *   - 缺文件:zip 缺白名单声明的文件 → extracted 集合据此可算出缺哪些
 *   - zip-slip:含 `../evil.csv` 路径穿越条目的包被 yauzl fail-closed **整包拒绝**(reject)
 *
 * fixtures 由 tests/fixtures/cold-import/*.zip 提供(python3 zipfile 预造,含合法 arcname `../`)。
 *
 * 跑:pnpm --filter @pac/service test -- cold-import-extract
 */
import * as fs from 'node:fs';
import * as os from 'node:os';
import * as path from 'node:path';
import { extractWhitelisted } from '../src/modules/admin/import-upload.service';

const FIX = path.join(__dirname, 'fixtures', 'cold-import');

function tmpDir(): string {
  return fs.mkdtempSync(path.join(os.tmpdir(), 'cold-import-test-'));
}

describe('extractWhitelisted', () => {
  it('只提取白名单命中的文件,忽略白名单外条目', async () => {
    const dest = tmpDir();
    try {
      const got = await extractWhitelisted(
        path.join(FIX, 'good.zip'),
        dest,
        new Set(['a.csv', 'b.csv']),
      );
      expect([...got].sort()).toEqual(['a.csv', 'b.csv']);
      expect(fs.existsSync(path.join(dest, 'a.csv'))).toBe(true);
      expect(fs.existsSync(path.join(dest, 'b.csv'))).toBe(true);
    } finally {
      fs.rmSync(dest, { recursive: true, force: true });
    }
  });

  it('缺文件:zip 缺声明文件 → extracted 不含它(供缺文件校验)', async () => {
    const dest = tmpDir();
    try {
      const whitelist = new Set(['a.csv', 'b.csv']);
      const got = await extractWhitelisted(path.join(FIX, 'partial.zip'), dest, whitelist);
      const missing = [...whitelist].filter((f) => !got.has(f));
      expect(missing).toEqual(['b.csv']);
    } finally {
      fs.rmSync(dest, { recursive: true, force: true });
    }
  });

  it('zip-slip:含 `../` 路径穿越条目的包被整包拒绝,且父目录零写入', async () => {
    const parent = tmpDir();
    const dest = path.join(parent, 'inner');
    fs.mkdirSync(dest);
    try {
      await expect(
        extractWhitelisted(path.join(FIX, 'evil.zip'), dest, new Set(['a.csv', 'evil.csv'])),
      ).rejects.toThrow(/relative path|invalid/i);
      // 关键:父目录绝无 evil.csv 写入(未逃逸)
      expect(fs.existsSync(path.join(parent, 'evil.csv'))).toBe(false);
    } finally {
      fs.rmSync(parent, { recursive: true, force: true });
    }
  });

  it('白名单外文件(c.csv)不落盘,子目录条目按 basename 落平', async () => {
    const dest = tmpDir();
    try {
      const got = await extractWhitelisted(
        path.join(FIX, 'extra.zip'),
        dest,
        new Set(['a.csv', 'nested.csv']),
      );
      expect([...got].sort()).toEqual(['a.csv', 'nested.csv']);
      expect(fs.existsSync(path.join(dest, 'a.csv'))).toBe(true);
      expect(fs.existsSync(path.join(dest, 'nested.csv'))).toBe(true); // sub/nested.csv → nested.csv
      expect(fs.existsSync(path.join(dest, 'c.csv'))).toBe(false); // 白名单外
    } finally {
      fs.rmSync(dest, { recursive: true, force: true });
    }
  });
});
