const test = require('node:test');
const assert = require('node:assert/strict');
const fs = require('node:fs');
const os = require('node:os');
const path = require('node:path');

const {
  projectOkfToHome,
  DEFAULT_TARGETS,
  MANAGED_REGION_START,
  MANAGED_REGION_END,
} = require('../lib/okf-project');

function makeFixtureHome() {
  return fs.mkdtempSync(path.join(os.tmpdir(), 'okf-project-home-'));
}

function readFile(filePath) {
  return fs.readFileSync(filePath, 'utf8');
}

function writeFile(filePath, content) {
  fs.mkdirSync(path.dirname(filePath), { recursive: true });
  fs.writeFileSync(filePath, content);
}

test('projectOkfToHome creates all managed targets inside the fixture home', () => {
  const homeDir = makeFixtureHome();

  const result = projectOkfToHome({
    homeDir,
    projectName: 'harness-nongated',
    projectRoot: '/repo/harness-nongated',
    okfRoot: '/repo/harness-nongated/.okf',
  });

  assert.deepEqual(Object.keys(result.files).sort(), Object.keys(DEFAULT_TARGETS).sort());

  for (const [targetName, relativePath] of Object.entries(DEFAULT_TARGETS)) {
    const targetPath = path.join(homeDir, relativePath);
    const content = readFile(targetPath);

    assert.equal(result.files[targetName].path, targetPath);
    assert.equal(result.files[targetName].changed, true);
    assert.match(content, new RegExp(MANAGED_REGION_START.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
    assert.match(content, new RegExp(MANAGED_REGION_END.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')));
    assert.match(content, /harness-nongated/);
    assert.match(content, /\/repo\/harness-nongated/);
    assert.match(content, /index\.md/);
  }
});

test('projectOkfToHome replaces only the managed region and is idempotent on rerun', () => {
  const homeDir = makeFixtureHome();
  const targetPath = path.join(homeDir, DEFAULT_TARGETS.CLAUDE_MD);

  writeFile(
    targetPath,
    [
      '# Local notes',
      '',
      MANAGED_REGION_START,
      'stale block',
      MANAGED_REGION_END,
      '',
      'tail matter',
      '',
    ].join('\n'),
  );

  const first = projectOkfToHome({
    homeDir,
    projectName: 'harness-nongated',
    projectRoot: '/repo/harness-nongated',
    okfRoot: '/repo/harness-nongated/.okf',
  });
  const afterFirstRun = readFile(targetPath);
  const second = projectOkfToHome({
    homeDir,
    projectName: 'harness-nongated',
    projectRoot: '/repo/harness-nongated',
    okfRoot: '/repo/harness-nongated/.okf',
  });
  const afterSecondRun = readFile(targetPath);

  assert.equal(first.files.CLAUDE_MD.changed, true);
  assert.equal(second.files.CLAUDE_MD.changed, false);
  assert.match(afterFirstRun, /^# Local notes/m);
  assert.match(afterFirstRun, /tail matter/);
  assert.equal((afterFirstRun.match(new RegExp(MANAGED_REGION_START, 'g')) || []).length, 1);
  assert.equal((afterFirstRun.match(new RegExp(MANAGED_REGION_END, 'g')) || []).length, 1);
  assert.equal(afterSecondRun, afterFirstRun);
});

test('projectOkfToHome writes targets by renaming temporary files in place', () => {
  const homeDir = makeFixtureHome();
  const originalRenameSync = fs.renameSync;
  const renames = [];

  fs.renameSync = (fromPath, toPath) => {
    renames.push({ fromPath, toPath });
    return originalRenameSync(fromPath, toPath);
  };

  try {
    projectOkfToHome({
      homeDir,
      projectName: 'harness-nongated',
      projectRoot: '/repo/harness-nongated',
      okfRoot: '/repo/harness-nongated/.okf',
    });
  } finally {
    fs.renameSync = originalRenameSync;
  }

  assert.equal(renames.length, Object.keys(DEFAULT_TARGETS).length);

  for (const rename of renames) {
    assert.equal(path.dirname(rename.fromPath), path.dirname(rename.toPath));
    assert.match(path.basename(rename.fromPath), /^\.okf-project\./);
    assert.equal(fs.existsSync(rename.fromPath), false);
    assert.equal(fs.existsSync(rename.toPath), true);
  }
});
