import { describe, expect, test } from "bun:test";
import { mkdtempSync, rmSync, unlinkSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { FeatureDefinitionSchema, loadFeatureDefinitions, loadRuntimeFeatureDefinitions, resolveRuntimeFeatureDefinition, trackedFeatureDefinitions } from "./definitions";

describe("feature definitions", () => {
  test("loads the tracked dark definition with a stable digest", () => {
    const definition = trackedFeatureDefinitions().get("controller-owned-dark-delivery");
    expect(definition?.definition.defaultState).toBe("OFF");
    expect(definition?.definition.introduced.task).toBe("#5");
    expect(definition?.digest).toMatch(/^[0-9a-f]{64}$/);
  });

  test("runtime loading disables the entire registry rather than throwing", () => {
    const missing = loadRuntimeFeatureDefinitions(join(tmpdir(), "does-not-exist-feature-definitions"));
    expect(missing.available).toBe(false);
    expect(missing.resolve("anything")).toMatchObject({ available: false, reason: "definition-unavailable" });
    const dir = mkdtempSync(join(tmpdir(), "feature-runtime-"));
    writeFileSync(join(dir, "bad.json"), "{");
    const invalid = loadRuntimeFeatureDefinitions(dir);
    expect(invalid.available).toBe(false);
    expect(invalid.resolve("valid-sibling")).toMatchObject({ available: false, reason: "invalid-definition" });
  });

  test("fails closed after review expiry and requires a cleanup task", () => {
    const definitions = trackedFeatureDefinitions();
    const registry = { available: true as const, definitions, resolve: (id: string) => {
      const definition = definitions.get(id);
      return definition ? { available: true as const, definition } : { available: false as const, reason: "missing-definition" as const, detail: { code: "not-found" } };
    } };
    expect(resolveRuntimeFeatureDefinition(registry, "controller-owned-dark-delivery", () => Date.parse("2026-09-12T00:00:00.000Z"))).toMatchObject({ available: false, reason: "expired-definition" });
    const definition = definitions.get("controller-owned-dark-delivery")!.definition;
    const { cleanupTask: _, ...withoutCleanupTask } = definition;
    expect(() => FeatureDefinitionSchema.parse(withoutCleanupTask)).toThrow();
  });

  test("rejects unknown keys, invalid dates, and duplicate IDs", () => {
    expect(() => FeatureDefinitionSchema.parse({ id: "test", changeClass: "docs" })).toThrow();
    const dir = mkdtempSync(join(tmpdir(), "feature-definitions-"));
    const valid = {
      id: "same", changeClass: "behavior-change", owner: "owner", fallback: "off",
      defaultState: "OFF", readinessChecks: ["receipt"], observability: ["ledger"],
      reviewDate: "2026-02-30", cleanupTask: "#5", rollbackWindowDays: 7, removalCondition: "remove", introduced: { task: "#5", sha: "a".repeat(40) }, activationPolicy: "dark-only",
    };
    writeFileSync(join(dir, "bad.json"), JSON.stringify(valid));
    expect(() => loadFeatureDefinitions(dir)).toThrow(/ISO calendar date/);
    unlinkSync(join(dir, "bad.json"));
    valid.reviewDate = "2026-02-28";
    writeFileSync(join(dir, "one.json"), JSON.stringify(valid));
    writeFileSync(join(dir, "two.json"), JSON.stringify(valid));
    expect(() => loadFeatureDefinitions(dir)).toThrow(/duplicate/);
    rmSync(dir, { recursive: true, force: true });
  });
});
