// EVIDENCE DRIVER for PR #23671 (not part of the PR); head only, the helpers do not exist at
// merge-base. Unit driver against withCheckpointRestoreReservation / withTurnStartReservation on
// real temp dirs. realPath/exists come from node:fs synchronously (real dirs, real results) so a
// forked reservation either enters or parks before the probe: "waiting" means the body has not
// run after PROBE_YIELDS x Effect.yieldNow. No sleeps, no TestClock.
import * as NodeFs from "node:fs";
import * as NodeServices from "@effect/platform-node/NodeServices";
import { expect, it } from "@effect/vitest";
import * as Deferred from "effect/Deferred";
import * as Effect from "effect/Effect";
import * as Exit from "effect/Exit";
import * as Fiber from "effect/Fiber";
import * as FileSystem from "effect/FileSystem";
import * as Path from "effect/Path";
import * as PlatformError from "effect/PlatformError";

import {
  withCheckpointRestoreReservation,
  withTurnStartReservation,
} from "./workspaceLease.ts";

const PROBE_YIELDS = 64;

const syncRealFileSystem = (real: FileSystem.FileSystem): FileSystem.FileSystem => ({
  ...real,
  exists: (target) => Effect.sync(() => NodeFs.existsSync(target)),
  realPath: (target) =>
    Effect.suspend(() => {
      try {
        return Effect.succeed(NodeFs.realpathSync(target));
      } catch {
        return Effect.fail(
          PlatformError.systemError({
            _tag: "NotFound",
            module: "FileSystem",
            method: "realPath",
            pathOrDescriptor: target,
          }),
        );
      }
    }),
});

const probe = Effect.gen(function* () {
  for (let i = 0; i < PROBE_YIELDS; i++) yield* Effect.yieldNow;
});

const row = (name: string, body: (env: {
  readonly dir: (relative: string) => string;
  readonly restore: <A, E>(cwd: string, effect: Effect.Effect<A, E>) => Effect.Effect<A, E>;
  readonly turnStart: <A, E>(cwd: string, effect: Effect.Effect<A, E>) => Effect.Effect<A, E>;
  readonly log: (line: string) => void;
}) => Effect.Effect<void, unknown>) =>
  it.effect(`HELPER ROW ${name}`, () =>
    Effect.gen(function* () {
      const real = yield* FileSystem.FileSystem;
      const path = yield* Path.Path;
      const fileSystem = syncRealFileSystem(real);
      const root = yield* real.realPath(
        yield* real.makeTempDirectoryScoped({ prefix: "t3-ev-23671-helper-" }),
      );
      for (const relative of ["b", "bc", "c", "b/child"]) {
        yield* real.makeDirectory(path.join(root, relative), { recursive: true });
      }
      const lines: Array<string> = [`ROW ${name}  (root=${root})`];
      yield* body({
        dir: (relative) => (relative === "" ? root : path.join(root, relative)),
        restore: (cwd, effect) => withCheckpointRestoreReservation(fileSystem, path, cwd, effect),
        turnStart: (cwd, effect) => withTurnStartReservation(fileSystem, path, cwd, effect),
        log: (line) => lines.push(`  ${String(lines.length).padStart(2)}. ${line}`),
      });
      lines.push("  PASS");
      console.log(lines.join("\n"));
    }).pipe(Effect.scoped, Effect.provide(NodeServices.layer)),
  );

const fork = <A, E>(effect: Effect.Effect<A, E>) =>
  effect.pipe(Effect.forkChild({ startImmediately: true }));

const entered = (log: (line: string) => void, label: string, flag: { value: boolean }) =>
  Effect.sync(() => {
    flag.value = true;
    log(`${label} entered`);
  });

row("1 non-overlapping dirs never wait (incl. <root>/b vs <root>/bc)", ({ dir, restore, turnStart, log }) =>
  Effect.gen(function* () {
    const releaseRestore = yield* Deferred.make<void>();
    const held = { value: false };
    const restoreFiber = yield* fork(
      restore(dir("b"), entered(log, "restore <root>/b (held)", held).pipe(Effect.andThen(Deferred.await(releaseRestore)))),
    );
    expect(held.value).toBe(true);
    for (const [kind, relative] of [
      ["turn start", "bc"],
      ["turn start", "c"],
      ["restore", "bc"],
      ["restore", "c"],
    ] as const) {
      const flag = { value: false };
      const label = `${kind} <root>/${relative} while restore <root>/b is held`;
      const run = kind === "restore" ? restore : turnStart;
      yield* Fiber.join(yield* fork(run(dir(relative), entered(log, label, flag))));
      expect(flag.value).toBe(true);
    }
    yield* Deferred.succeed(releaseRestore, undefined);
    yield* Fiber.join(restoreFiber);
    log("restore <root>/b released");
  }),
);

row("2 two turn starts on the same dir (and nested) never wait", ({ dir, turnStart, log }) =>
  Effect.gen(function* () {
    const releaseFirst = yield* Deferred.make<void>();
    const first = { value: false };
    const firstFiber = yield* fork(
      turnStart(dir("b"), entered(log, "turn start A <root>/b (held)", first).pipe(Effect.andThen(Deferred.await(releaseFirst)))),
    );
    expect(first.value).toBe(true);
    const same = { value: false };
    yield* Fiber.join(yield* fork(turnStart(dir("b"), entered(log, "turn start B <root>/b while A held", same))));
    const nested = { value: false };
    yield* Fiber.join(yield* fork(turnStart(dir("b/child"), entered(log, "turn start C <root>/b/child while A held", nested))));
    expect(same.value && nested.value).toBe(true);
    yield* Deferred.succeed(releaseFirst, undefined);
    yield* Fiber.join(firstFiber);
    log("turn start A released");
  }),
);

const releasesAfter = (name: string, failing: Effect.Effect<never, string>, expectExit: (exit: Exit.Exit<never, string>) => string) =>
  row(name, ({ dir, restore, turnStart, log }) =>
    Effect.gen(function* () {
      const exit = yield* Effect.exit(restore(dir("b"), failing));
      log(`restore <root>/b exited: ${expectExit(exit)}`);
      const flag = { value: false };
      const later = yield* fork(turnStart(dir("b/child"), entered(log, "later turn start <root>/b/child", flag)));
      yield* probe;
      log(`after ${PROBE_YIELDS}x yieldNow: later turn start ${flag.value ? "ENTERED immediately" : "still WAITING"}`);
      expect(flag.value).toBe(true);
      yield* Fiber.join(later);
    }),
  );

releasesAfter("3 restore failure (Effect.fail) releases", Effect.fail("restore failed"), (exit) => {
  expect(Exit.isFailure(exit) && exit.cause.reasons.some((r) => r._tag === "Fail")).toBe(true);
  return "Fail(\"restore failed\")";
});

releasesAfter("5 restore defect (Effect.die) releases", Effect.die("restore defect"), (exit) => {
  expect(Exit.isFailure(exit) && exit.cause.reasons.some((r) => r._tag === "Die")).toBe(true);
  return "Die(\"restore defect\")";
});

row("4 restore interrupted releases; a parked turn start then proceeds", ({ dir, restore, turnStart, log }) =>
  Effect.gen(function* () {
    const never = yield* Deferred.make<void>();
    const held = { value: false };
    const restoreFiber = yield* fork(
      restore(dir("b"), entered(log, "restore <root>/b (parked forever)", held).pipe(Effect.andThen(Deferred.await(never)))),
    );
    const flag = { value: false };
    const waiting = yield* fork(turnStart(dir("b/child"), entered(log, "turn start <root>/b/child", flag)));
    yield* probe;
    log(`after ${PROBE_YIELDS}x yieldNow: turn start ${flag.value ? "ENTERED" : "WAITING"} while restore held`);
    expect(flag.value).toBe(false);
    yield* Fiber.interrupt(restoreFiber);
    log("restore fiber interrupted");
    yield* Fiber.join(waiting);
    expect(flag.value).toBe(true);
  }),
);

row("6 turn start interrupted while parked holds nothing; a later restore enters immediately", ({ dir, restore, turnStart, log }) =>
  Effect.gen(function* () {
    const releaseFirst = yield* Deferred.make<void>();
    const first = { value: false };
    const firstFiber = yield* fork(
      restore(dir("b"), entered(log, "restore R1 <root>/b (held)", first).pipe(Effect.andThen(Deferred.await(releaseFirst)))),
    );
    const turn = { value: false };
    const turnFiber = yield* fork(turnStart(dir("b"), entered(log, "turn start <root>/b", turn)));
    yield* probe;
    log(`after ${PROBE_YIELDS}x yieldNow: turn start ${turn.value ? "ENTERED" : "WAITING"}`);
    expect(turn.value).toBe(false);
    yield* Fiber.interrupt(turnFiber);
    log("parked turn start interrupted");
    yield* Deferred.succeed(releaseFirst, undefined);
    yield* Fiber.join(firstFiber);
    log("restore R1 released");
    const second = { value: false };
    const secondFiber = yield* fork(restore(dir("b"), entered(log, "restore R2 <root>/b", second)));
    yield* probe;
    log(`after ${PROBE_YIELDS}x yieldNow: restore R2 ${second.value ? "ENTERED immediately" : "WAITING"}; interrupted turn body ran: ${turn.value}`);
    expect(second.value).toBe(true);
    expect(turn.value).toBe(false);
    yield* Fiber.join(secondFiber);
  }),
);

row("7 two overlapping restores serialize", ({ dir, restore, log }) =>
  Effect.gen(function* () {
    const releaseFirst = yield* Deferred.make<void>();
    const first = { value: false };
    const firstFiber = yield* fork(
      restore(dir("b"), entered(log, "restore R1 <root>/b (held)", first).pipe(Effect.andThen(Deferred.await(releaseFirst)))),
    );
    const second = { value: false };
    const secondFiber = yield* fork(restore(dir("b/child"), entered(log, "restore R2 <root>/b/child", second)));
    yield* probe;
    log(`after ${PROBE_YIELDS}x yieldNow: R2 ${second.value ? "ENTERED" : "WAITING"} while R1 held`);
    expect(second.value).toBe(false);
    yield* Deferred.succeed(releaseFirst, undefined);
    log("R1 released");
    yield* Fiber.join(firstFiber);
    yield* Fiber.join(secondFiber);
    expect(second.value).toBe(true);
  }),
);

row("8 held turn start, then a restore waits until the turn start finishes", ({ dir, restore, turnStart, log }) =>
  Effect.gen(function* () {
    const releaseTurn = yield* Deferred.make<void>();
    const turn = { value: false };
    const turnFiber = yield* fork(
      turnStart(dir("b"), entered(log, "turn start <root>/b (held)", turn).pipe(Effect.andThen(Deferred.await(releaseTurn)))),
    );
    const restored = { value: false };
    const restoreFiber = yield* fork(restore(dir(""), entered(log, "restore <root> (parent)", restored)));
    yield* probe;
    log(`after ${PROBE_YIELDS}x yieldNow: restore ${restored.value ? "ENTERED" : "WAITING"} while turn start held`);
    expect(restored.value).toBe(false);
    yield* Deferred.succeed(releaseTurn, undefined);
    log("turn start released");
    yield* Fiber.join(turnFiber);
    yield* Fiber.join(restoreFiber);
    expect(restored.value).toBe(true);
  }),
);
