import { mkdirSync, readFileSync, rmSync, writeFileSync } from "node:fs";
import { tmpdir } from "node:os";
import { join } from "node:path";
import { afterEach, beforeEach, describe, expect, it } from "vitest";
import {
	EXIT_BLOCKED,
	EXIT_CANCELLED,
	EXIT_ERROR,
	EXIT_RELOAD,
	EXIT_SUCCESS,
	mapStatusToExitCode,
} from "../../../../../dist/headless-events.js";
import { detectProjectSignals } from "../detection.js";
import {
	_resetNotificationStore,
	appendNotification,
	initNotificationStore,
} from "../notification-store.js";

describe("S08 HIGH: notification + detection + headless", () => {
	describe("EXIT_RELOAD exit code mapping", () => {
		it("should map reload status to EXIT_RELOAD (12)", () => {
			expect(mapStatusToExitCode("reload")).toBe(EXIT_RELOAD);
		});

		it("should not fall through to EXIT_ERROR for reload", () => {
			expect(mapStatusToExitCode("reload")).not.toBe(EXIT_ERROR);
		});

		it("should map all known statuses correctly", () => {
			expect(mapStatusToExitCode("success")).toBe(EXIT_SUCCESS);
			expect(mapStatusToExitCode("complete")).toBe(EXIT_SUCCESS);
			expect(mapStatusToExitCode("completed")).toBe(EXIT_SUCCESS);
			expect(mapStatusToExitCode("error")).toBe(EXIT_ERROR);
			expect(mapStatusToExitCode("timeout")).toBe(EXIT_ERROR);
			expect(mapStatusToExitCode("blocked")).toBe(EXIT_BLOCKED);
			expect(mapStatusToExitCode("cancelled")).toBe(EXIT_CANCELLED);
			expect(mapStatusToExitCode("reload")).toBe(EXIT_RELOAD);
		});

		it("should default unknown status to EXIT_ERROR", () => {
			expect(mapStatusToExitCode("unknown")).toBe(EXIT_ERROR);
		});
	});

	describe("deduplication off-by-one fix", () => {
		let testDir;

		beforeEach(() => {
			_resetNotificationStore();
			testDir = join(tmpdir(), `sf-dedup-test-${Date.now()}`);
			mkdirSync(testDir, { recursive: true });
			initNotificationStore(testDir);
		});

		it("should deduplicate rapid identical notifications", () => {
			appendNotification("test message", "info", "test", {
				dedupe_key: "rapid-test",
				blocking: true,
			});
			// Small delay to ensure first write completes
			const start = Date.now();
			while (Date.now() - start < 10) {
				/* spin */
			}
			appendNotification("test message", "info", "test", {
				dedupe_key: "rapid-test",
				blocking: true,
			});
			const content = readFileSync(
				join(testDir, ".sf", "notifications.jsonl"),
				"utf-8",
			);
			const lines = content.trim().split("\n").filter(Boolean);
			expect(lines.length).toBe(1);
		});

		it("should suppress repeated persisted notifications across restarts", () => {
			appendNotification("quota warning", "warning", "notify", {
				dedupe_key: "quota-warning",
			});
			_resetNotificationStore();
			initNotificationStore(testDir);
			appendNotification("quota warning", "warning", "notify", {
				dedupe_key: "quota-warning",
			});

			const content = readFileSync(
				join(testDir, ".sf", "notifications.jsonl"),
				"utf-8",
			);
			const lines = content.trim().split("\n").filter(Boolean);
			expect(lines.length).toBe(1);
		});
	});

	describe("ROOT_ONLY_PROJECT_FILES root-only detection", () => {
		let testDir;

		beforeEach(() => {
			testDir = join(tmpdir(), `sf-detection-test-${Date.now()}`);
			mkdirSync(testDir, { recursive: true });
		});

		afterEach(() => {
			try {
				rmSync(testDir, { recursive: true });
			} catch {}
		});

		it("should detect package.json only at root, not in nested dirs", () => {
			// Create root package.json
			writeFileSync(
				join(testDir, "package.json"),
				JSON.stringify({ name: "root" }),
				"utf-8",
			);
			// Create nested package.json
			mkdirSync(join(testDir, "packages", "a"), { recursive: true });
			writeFileSync(
				join(testDir, "packages", "a", "package.json"),
				JSON.stringify({ name: "nested" }),
				"utf-8",
			);

			const signals = detectProjectSignals(testDir);
			// Should include root package.json
			expect(signals.detectedFiles).toContain("package.json");
			// Should NOT include nested package.json as a root marker
			// (the detectedFiles list only has "package.json" once, from root)
			expect(
				signals.detectedFiles.filter((f) => f === "package.json").length,
			).toBe(1);
		});

		it("should not include nested Cargo.toml in detectedFiles", () => {
			mkdirSync(join(testDir, "crates", "a"), { recursive: true });
			writeFileSync(
				join(testDir, "crates", "a", "Cargo.toml"),
				'[package]\nname="nested"',
				"utf-8",
			);

			const signals = detectProjectSignals(testDir);
			// Cargo.toml should not be in detectedFiles since it's nested and ROOT_ONLY
			expect(signals.detectedFiles).not.toContain("Cargo.toml");
		});
	});
});
