import assert from 'node:assert/strict';
import { access, mkdir, readFile, readdir, rm, writeFile } from 'node:fs/promises';
import path from 'node:path';
import test from 'node:test';

import { installHooks } from './install-hooks.mjs';

const fixtureRoot = path.join(process.cwd(), '.mosaic-test-work', `hooks-${process.pid}`);
const quarantineRoot = path.join(fixtureRoot, 'quarantine');

async function fixture(name) {
  const root = path.join(fixtureRoot, name);
  await mkdir(path.join(root, '.husky'), { recursive: true });
  return root;
}

async function exists(target) {
  try {
    await access(target);
    return true;
  } catch {
    return false;
  }
}

test.after(async () => {
  await rm(fixtureRoot, { recursive: true, force: true });
});

test('an interrupted install quarantines the partial active hook set and fails loudly', async () => {
  const root = await fixture('interrupted');
  let restoredHooksPath = 'not-called';

  await assert.rejects(
    installHooks({
      root,
      quarantineRoot,
      runHusky: async (stagingHooks) => {
        await mkdir(path.join(stagingHooks, '_'), { recursive: true });
        await writeFile(path.join(stagingHooks, '_', 'h'), 'partial');
        throw new Error('simulated interruption');
      },
      activateHooks: async () => {},
      readHooksPath: async () => null,
      restoreHooksPath: async (value) => {
        restoredHooksPath = value;
      },
    }),
    (error) => {
      assert.match(error.message, /Hook installation failed/);
      assert.match(error.message, /pnpm install --frozen-lockfile/);
      return true;
    },
  );

  assert.equal(await exists(path.join(root, '.husky', '_')), false);
  assert.equal(restoredHooksPath, 'not-called');
  const quarantined = await readdir(quarantineRoot);
  assert.equal(quarantined.length, 1);
});

test('a failed replacement restores a previously complete active hook set', async () => {
  const root = await fixture('rollback');
  const activeShim = path.join(root, '.husky', '_', 'h');
  await mkdir(path.dirname(activeShim), { recursive: true });
  await writeFile(activeShim, 'previous-complete');
  let previousRemainedActiveDuringStaging = false;

  await assert.rejects(
    installHooks({
      root,
      quarantineRoot: path.join(fixtureRoot, 'rollback-quarantine'),
      runHusky: async () => {
        previousRemainedActiveDuringStaging =
          (await readFile(activeShim, 'utf8')) === 'previous-complete';
        throw new Error('simulated replacement failure');
      },
      activateHooks: async () => {},
      readHooksPath: async () => '.husky/_',
      restoreHooksPath: async () => {},
    }),
    /Hook installation failed/,
  );

  assert.equal(previousRemainedActiveDuringStaging, true);
  assert.equal(await readFile(activeShim, 'utf8'), 'previous-complete');
});

test('a mismatched complete hook set fails loudly instead of reporting a stale install as current', async () => {
  const root = await fixture('mismatch');
  const activeShim = path.join(root, '.husky', '_', 'h');
  await mkdir(path.dirname(activeShim), { recursive: true });
  await writeFile(activeShim, 'old-complete');

  await assert.rejects(
    installHooks({
      root,
      quarantineRoot: path.join(fixtureRoot, 'mismatch-quarantine'),
      runHusky: async (stagingHooks) => {
        await mkdir(path.join(stagingHooks, '_'), { recursive: true });
        await writeFile(path.join(stagingHooks, '_', 'h'), 'new-complete');
      },
      activateHooks: async () => {},
      readHooksPath: async () => '.husky/_',
      restoreHooksPath: async () => {},
    }),
    /Hook installation failed.*pnpm install --frozen-lockfile/,
  );

  assert.equal(await readFile(activeShim, 'utf8'), 'old-complete');
});

test('a competing successful installer is not removed by the losing process', async () => {
  const root = await fixture('concurrent');
  const activeShim = path.join(root, '.husky', '_', 'h');
  let restored = false;

  await assert.rejects(
    installHooks({
      root,
      quarantineRoot: path.join(fixtureRoot, 'concurrent-quarantine'),
      runHusky: async (stagingHooks) => {
        await mkdir(path.join(stagingHooks, '_'), { recursive: true });
        await writeFile(path.join(stagingHooks, '_', 'h'), 'ours');
        await mkdir(path.dirname(activeShim), { recursive: true });
        await writeFile(activeShim, 'peer');
      },
      activateHooks: async () => {},
      readHooksPath: async () => null,
      restoreHooksPath: async () => {
        restored = true;
      },
    }),
    /Hook installation failed/,
  );

  assert.equal(await readFile(activeShim, 'utf8'), 'peer');
  assert.equal(restored, false);
});

test("a competing installer that replaces this installer's active set is preserved", async () => {
  const root = await fixture('concurrent-after-rename');
  const active = path.join(root, '.husky', '_');
  const activeShim = path.join(active, 'h');
  let restored = false;

  await assert.rejects(
    installHooks({
      root,
      quarantineRoot: path.join(fixtureRoot, 'concurrent-after-rename-quarantine'),
      runHusky: async (stagingHooks) => {
        await mkdir(path.join(stagingHooks, '_'), { recursive: true });
        await writeFile(path.join(stagingHooks, '_', 'h'), 'ours');
      },
      activateHooks: async () => {
        await rm(active, { recursive: true, force: true });
        await mkdir(active, { recursive: true });
        await writeFile(activeShim, 'peer');
        throw new Error('our activation lost to peer');
      },
      readHooksPath: async () => null,
      restoreHooksPath: async () => {
        restored = true;
      },
    }),
    /Hook installation failed/,
  );

  assert.equal(await readFile(activeShim, 'utf8'), 'peer');
  assert.equal(restored, false);
});

test('an explicit interactive HUSKY=0 opt-out preserves existing hooks without running installer', async () => {
  const root = await fixture('disabled');
  const activeShim = path.join(root, '.husky', '_', 'h');
  await mkdir(path.dirname(activeShim), { recursive: true });
  await writeFile(activeShim, 'preserved');
  let ran = false;

  await installHooks({
    root,
    disabled: true,
    runHusky: async () => {
      ran = true;
    },
  });

  assert.equal(ran, false);
  assert.equal(await readFile(activeShim, 'utf8'), 'preserved');
});

test('a successful install leaves a complete active hook set', async () => {
  const root = await fixture('success');

  await installHooks({
    root,
    quarantineRoot,
    runHusky: async (stagingHooks) => {
      await mkdir(path.join(stagingHooks, '_'), { recursive: true });
      await writeFile(path.join(stagingHooks, '_', 'h'), 'complete');
    },
    activateHooks: async () => {},
    readHooksPath: async () => null,
    restoreHooksPath: async () => {},
  });

  assert.equal(await exists(path.join(root, '.husky', '_', 'h')), true);
});
