import { afterEach, beforeEach, describe, expect, test } from "bun:test";
import { mkdtempSync, readdirSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { abandonRun, readAbandoned, restoreRun } from "./abandoned-store";

let configPath: string;
let previousConfigDir: string | undefined;

beforeEach(() => {
  configPath = mkdtempSync(join(tmpdir(), "overdeck-abandoned-"));
  previousConfigDir = process.env.OVERDECK_CONFIG_DIR;
  process.env.OVERDECK_CONFIG_DIR = configPath;
});

afterEach(() => {
  if (previousConfigDir === undefined) delete process.env.OVERDECK_CONFIG_DIR;
  else process.env.OVERDECK_CONFIG_DIR = previousConfigDir;
  rmSync(configPath, { recursive: true, force: true });
});

describe("abandoned plan store", () => {
  test("missing and corrupt stores read as empty without throwing", () => {
    expect(readAbandoned()).toEqual({});

    const originalWarn = console.warn;
    const warnings: string[] = [];
    console.warn = (message?: unknown) => warnings.push(String(message));
    try {
      writeFileSync(join(configPath, "abandoned-plans.json"), "not-json");
      expect(readAbandoned()).toEqual({});
      expect(readAbandoned()).toEqual({});
    } finally {
      console.warn = originalWarn;
    }
    expect(warnings).toHaveLength(1);
  });

  test("abandon is restart-safe, idempotent, and atomically persisted", () => {
    abandonRun("run-1", () => "2026-07-19T10:00:00.000Z");
    abandonRun("run-1", () => "2026-07-19T11:00:00.000Z");

    expect(readAbandoned()).toEqual({
      "run-1": { abandonedAt: "2026-07-19T10:00:00.000Z" },
    });
    expect(readdirSync(configPath)).toEqual(["abandoned-plans.json"]);
  });

  test("restore is idempotent", () => {
    abandonRun("run-1", () => "2026-07-19T10:00:00.000Z");

    restoreRun("run-1");
    restoreRun("run-1");

    expect(readAbandoned()).toEqual({});
  });
});
