import { mkdirSync, writeFileSync } from "node:fs";
import { join } from "node:path";

import { describe, expect, it } from "vitest";

import {
  CAPACITY_COUNTED_FILE_KINDS,
  CAPACITY_EXCLUDED_STORAGE,
  HARD_LIMIT_BYTES,
  classifyCapacity,
  decideStorageAction,
} from "../../apps/api/src/storage-policy.js";

describe("TDD-WP0-STO-001-byte-thresholds", () => {
  it.each([
    [4_294_967_295, "normal", "active"],
    [4_294_967_296, "warning", "active"],
    [4_831_838_207, "warning", "active"],
    [4_831_838_208, "critical", "active"],
    [5_368_709_119, "critical", "active"],
    [5_368_709_120, "critical", "full"],
    [5_368_709_121, "critical", "full"],
  ] as const)("classifies %i bytes", (bytes, notice, status) => {
    expect(classifyCapacity(bytes, 0)).toEqual({ capacity_notice_level: notice, storage_status: status });
  });

  it("records the deterministic threshold result without deleting content", () => {
    const values = [
      4_294_967_295,
      4_294_967_296,
      4_831_838_207,
      4_831_838_208,
      5_368_709_119,
      HARD_LIMIT_BYTES,
      5_368_709_121,
    ].map((bytes) => ({ bytes, ...classifyCapacity(bytes, 0) }));
    const directory = process.env.DADA_EVIDENCE_DIR_STO_001;
    if (directory) {
      mkdirSync(directory, { recursive: true });
      writeFileSync(join(directory, "thresholds.json"), `${JSON.stringify({ automatic_cleanup: false, values }, null, 2)}\n`);
      writeFileSync(join(directory, "db-diff.json"), `${JSON.stringify({ changed_fields: ["managed_content_bytes", "capacity_notice_level", "storage_status", "measured_at"], deleted_files: 0 }, null, 2)}\n`);
    }
  });

  it("counts only managed binary classes and excludes infrastructure and downloads", () => {
    expect(CAPACITY_COUNTED_FILE_KINDS).toEqual([
      "reference", "generated", "export", "derived", "sticker_original", "sticker_thumbnail",
    ]);
    expect(CAPACITY_EXCLUDED_STORAGE).toEqual([
      "read_only_assets", "application_files", "database", "logs", "audit", "browser_cache", "user_downloads",
    ]);
  });
});

describe("TDD-WP0-STO-003 action matrices", () => {
  it("allows only the frozen full-state actions", () => {
    expect(decideStorageAction("full", true, "project_json_write")).toBe("allow");
    expect(decideStorageAction("full", true, "read")).toBe("allow");
    expect(decideStorageAction("full", true, "download")).toBe("allow");
    expect(decideStorageAction("full", true, "client_only_download")).toBe("allow");
    expect(decideStorageAction("full", true, "permanent_delete")).toBe("allow");
    expect(decideStorageAction("full", true, "explicit_cleanup")).toBe("allow");
    expect(decideStorageAction("full", true, "binary_write")).toBe("reject_capacity");
    expect(decideStorageAction("full", true, "ai_call")).toBe("reject_capacity");
    expect(decideStorageAction("full", true, "latest_export_write")).toBe("reject_capacity");
  });

  it("blocks all new backend writes while unavailable and gates cleanup on SQLite", () => {
    for (const action of ["project_json_write", "binary_write", "ai_call", "latest_export_write"] as const) {
      expect(decideStorageAction("unavailable", true, action)).toBe("reject_unavailable");
    }
    for (const action of ["read", "download", "client_only_download"] as const) {
      expect(decideStorageAction("unavailable", false, action)).toBe("allow");
    }
    expect(decideStorageAction("unavailable", true, "permanent_delete")).toBe("allow");
    expect(decideStorageAction("unavailable", false, "permanent_delete")).toBe("reject_uncommitted");
    expect(decideStorageAction("unavailable", true, "explicit_cleanup")).toBe("allow");
    expect(decideStorageAction("unavailable", false, "explicit_cleanup")).toBe("reject_uncommitted");
  });
});
