import { describe, it, expect, beforeEach, afterEach, vi } from 'vitest';
import { mkdtemp, mkdir, readFile, writeFile, rm, copyFile, readdir } from 'node:fs/promises';
import { join, resolve } from 'node:path';
import { tmpdir } from 'node:os';

const PROJECT_ROOT = resolve(import.meta.dirname, '..', '..');
const REAL_SEED_DIR = join(PROJECT_ROOT, 'public', 'content');
let workDir: string;
type ContentModule = typeof import('../../src/lib/content');
let content: ContentModule;

async function setupTmpRoot() {
  workDir = await mkdtemp(join(tmpdir(), 'portfolio-content-'));
  await mkdir(join(workDir, 'data', 'content'), { recursive: true });
  const tmpSeedDir = join(workDir, 'public', 'content');
  await mkdir(tmpSeedDir, { recursive: true });
  for (const file of await readdir(REAL_SEED_DIR)) {
    await copyFile(join(REAL_SEED_DIR, file), join(tmpSeedDir, file));
  }
  vi.spyOn(process, 'cwd').mockReturnValue(workDir);
  vi.resetModules();
  content = await import('../../src/lib/content');
}

async function cleanup() {
  vi.restoreAllMocks();
  if (workDir) await rm(workDir, { recursive: true, force: true });
}

beforeEach(setupTmpRoot);
afterEach(cleanup);

describe('loadContent', () => {
  it('copie le seed depuis public/content quand data/content/<key>.json est absent', async () => {
    const profile = await content.loadContent('profile');
    expect(profile.name).toBeTruthy();
    const dataFile = await readFile(join(workDir, 'data', 'content', 'profile.json'), 'utf-8');
    expect(JSON.parse(dataFile).name).toBe(profile.name);
  });

  it('lit data/content/<key>.json quand il existe (pas le seed)', async () => {
    const seed = JSON.parse(
      await readFile(join(workDir, 'public', 'content', 'profile.json'), 'utf-8'),
    );
    const customized = { ...seed, name: 'CustomFromData' };
    await writeFile(
      join(workDir, 'data', 'content', 'profile.json'),
      JSON.stringify(customized),
      'utf-8',
    );
    const profile = await content.loadContent('profile');
    expect(profile.name).toBe('CustomFromData');
  });
});

describe('saveContent', () => {
  it('écrit data/content/<key>.json et retourne les données validées', async () => {
    const seed = JSON.parse(
      await readFile(join(workDir, 'public', 'content', 'profile.json'), 'utf-8'),
    );
    const updated = { ...seed, name: 'NouveauNom' };
    const saved = await content.saveContent('profile', updated);
    expect(saved.name).toBe('NouveauNom');
    const onDisk = JSON.parse(
      await readFile(join(workDir, 'data', 'content', 'profile.json'), 'utf-8'),
    );
    expect(onDisk.name).toBe('NouveauNom');
  });

  it('rejette un payload invalide (ZodError)', async () => {
    await expect(content.saveContent('profile', { bogus: true })).rejects.toThrow();
  });

  it('rejette null', async () => {
    await expect(content.saveContent('profile', null)).rejects.toThrow();
  });
});
