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 { isMilestoneReadyText } from "../../../../../dist/headless-events.js";
import {
	_resetNotificationStore,
	appendNotification,
	initNotificationStore,
	readNotifications,
} from "../notification-store.js";

describe("S08 MEDIUM: notification + detection + headless", () => {
	describe("stale lock NaN detection", () => {
		let testDir;

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

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

		it("should treat NaN lock timestamp as stale and allow operation", () => {
			// Create a lock file with NaN content (simulating crash mid-write)
			const lockPath = join(testDir, ".sf", "notifications.lock");
			mkdirSync(join(testDir, ".sf"), { recursive: true });
			writeFileSync(lockPath, "not-a-number", "utf-8");

			// This should succeed because NaN lock is treated as stale
			appendNotification("test message", "info", "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 not persist non-actionable startup status notifications", () => {
			appendNotification("MCP client ready — 2 server(s) configured", "info");

			expect(() =>
				readFileSync(join(testDir, ".sf", "notifications.jsonl"), "utf-8"),
			).toThrow();
		});

		it("should persist actionable info notifications", () => {
			appendNotification("operator input required", "info", "notify", {
				kind: "terminal",
			});

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

		it("should treat legacy notifications without schemaVersion as version 1", () => {
			const filePath = join(testDir, ".sf", "notifications.jsonl");
			mkdirSync(join(testDir, ".sf"), { recursive: true });
			writeFileSync(
				filePath,
				JSON.stringify({
					id: "legacy-1",
					ts: "2026-05-07T00:00:00.000Z",
					severity: "warning",
					message: "legacy warning",
					source: "test",
				}) + "\n",
				"utf-8",
			);

			const [entry] = readNotifications(testDir);

			expect(entry.schemaVersion).toBe(1);
			expect(entry.read).toBe(false);
		});
	});

	describe("milestone-ready text detection", () => {
		it("should match milestone ready text in buffer", () => {
			expect(isMilestoneReadyText("milestone M001 ready")).toBe(true);
			expect(isMilestoneReadyText("Milestone M001 is ready for review")).toBe(
				true,
			);
		});

		it("should not match unrelated text", () => {
			expect(isMilestoneReadyText("some random text")).toBe(false);
			expect(isMilestoneReadyText("milestone")).toBe(false);
		});
	});
});

describe("S08 LOW: notification + detection + headless", () => {
	describe("autonomous mode visibility restrictions", () => {
		it("should detect milestone ready in text delta", () => {
			expect(isMilestoneReadyText("milestone M008 ready")).toBe(true);
		});

		it("should be case insensitive", () => {
			expect(isMilestoneReadyText("MILESTONE M008 READY")).toBe(true);
		});
	});
});
