/**
 * R090/S01 — unit-lanes module tests.
 *
 * Covers:
 *   - classifyUnitLane: each known type, fallback for unknown
 *   - areLanesEnabled: default (on), SF_LANES=0, SF_LANES=false
 *   - getPlanningLaneCapacity / getExecuteLaneCapacity: defaults and overrides
 *   - selectLaneAwareUnits: basic selection and cross-lane scan behaviour
 */
import { describe, expect, it } from "vitest";
import {
	LANE_EXECUTE,
	LANE_PLANNING,
	areLanesEnabled,
	classifyUnitLane,
	getExecuteLaneCapacity,
	getPlanningLaneCapacity,
	selectLaneAwareUnits,
} from "../auto/unit-lanes.js";

// ── classifyUnitLane ──────────────────────────────────────────────────────────

describe("classifyUnitLane — explicit planning types", () => {
	it("classifies plan-milestone as planning", () => {
		expect(classifyUnitLane("plan-milestone")).toBe(LANE_PLANNING);
	});

	it("classifies plan-slice as planning", () => {
		expect(classifyUnitLane("plan-slice")).toBe(LANE_PLANNING);
	});

	it("classifies research-slice as planning", () => {
		expect(classifyUnitLane("research-slice")).toBe(LANE_PLANNING);
	});

	it("classifies assess-slice as planning", () => {
		expect(classifyUnitLane("assess-slice")).toBe(LANE_PLANNING);
	});

	it("classifies synthesize-slice as planning", () => {
		expect(classifyUnitLane("synthesize-slice")).toBe(LANE_PLANNING);
	});

	it("classifies reassess-roadmap as planning", () => {
		expect(classifyUnitLane("reassess-roadmap")).toBe(LANE_PLANNING);
	});

	it("classifies validate-milestone as planning", () => {
		expect(classifyUnitLane("validate-milestone")).toBe(LANE_PLANNING);
	});
});

describe("classifyUnitLane — prefix/suffix rules", () => {
	it("classifies arbitrary plan-* types as planning", () => {
		expect(classifyUnitLane("plan-whatever")).toBe(LANE_PLANNING);
		expect(classifyUnitLane("plan-deep-dive")).toBe(LANE_PLANNING);
	});

	it("classifies arbitrary research-* types as planning", () => {
		expect(classifyUnitLane("research-codebase")).toBe(LANE_PLANNING);
	});

	it("classifies types ending in -research as planning", () => {
		expect(classifyUnitLane("deep-research")).toBe(LANE_PLANNING);
		expect(classifyUnitLane("codebase-research")).toBe(LANE_PLANNING);
	});
});

describe("classifyUnitLane — execute types", () => {
	it("classifies execute-task as execute", () => {
		expect(classifyUnitLane("execute-task")).toBe(LANE_EXECUTE);
	});

	it("classifies complete-task as execute", () => {
		expect(classifyUnitLane("complete-task")).toBe(LANE_EXECUTE);
	});

	it("classifies complete-slice as execute", () => {
		expect(classifyUnitLane("complete-slice")).toBe(LANE_EXECUTE);
	});

	it("classifies complete-milestone as execute", () => {
		expect(classifyUnitLane("complete-milestone")).toBe(LANE_EXECUTE);
	});

	it("classifies repair-* as execute", () => {
		expect(classifyUnitLane("repair-something")).toBe(LANE_EXECUTE);
		expect(classifyUnitLane("repair-slice")).toBe(LANE_EXECUTE);
	});
});

describe("classifyUnitLane — fallback for unknown types", () => {
	it("defaults unknown types to execute lane", () => {
		expect(classifyUnitLane("completely-unknown-type")).toBe(LANE_EXECUTE);
		expect(classifyUnitLane("deploy")).toBe(LANE_EXECUTE);
		expect(classifyUnitLane("run-uat")).toBe(LANE_EXECUTE);
	});

	it("handles empty string as execute", () => {
		expect(classifyUnitLane("")).toBe(LANE_EXECUTE);
	});

	it("handles non-string as execute", () => {
		expect(classifyUnitLane(null)).toBe(LANE_EXECUTE);
		expect(classifyUnitLane(undefined)).toBe(LANE_EXECUTE);
		expect(classifyUnitLane(42)).toBe(LANE_EXECUTE);
	});
});

// ── areLanesEnabled ───────────────────────────────────────────────────────────

describe("areLanesEnabled", () => {
	it("returns true when SF_LANES is not set", () => {
		expect(areLanesEnabled({})).toBe(true);
	});

	it("returns true when SF_LANES=1", () => {
		expect(areLanesEnabled({ SF_LANES: "1" })).toBe(true);
	});

	it("returns true when SF_LANES=true", () => {
		expect(areLanesEnabled({ SF_LANES: "true" })).toBe(true);
	});

	it("returns false when SF_LANES=0", () => {
		expect(areLanesEnabled({ SF_LANES: "0" })).toBe(false);
	});

	it("returns false when SF_LANES=false", () => {
		expect(areLanesEnabled({ SF_LANES: "false" })).toBe(false);
	});
});

// ── getPlanningLaneCapacity ───────────────────────────────────────────────────

describe("getPlanningLaneCapacity", () => {
	it("returns 1 by default", () => {
		expect(getPlanningLaneCapacity({})).toBe(1);
	});

	it("returns the override value when SF_LANES_PLANNING_N is set", () => {
		expect(getPlanningLaneCapacity({ SF_LANES_PLANNING_N: "3" })).toBe(3);
	});

	it("ignores invalid values and returns default", () => {
		expect(getPlanningLaneCapacity({ SF_LANES_PLANNING_N: "abc" })).toBe(1);
		expect(getPlanningLaneCapacity({ SF_LANES_PLANNING_N: "0" })).toBe(1);
		expect(getPlanningLaneCapacity({ SF_LANES_PLANNING_N: "-1" })).toBe(1);
	});
});

// ── getExecuteLaneCapacity ────────────────────────────────────────────────────

describe("getExecuteLaneCapacity", () => {
	it("returns 1 by default", () => {
		expect(getExecuteLaneCapacity({})).toBe(1);
	});

	it("returns the override value when SF_LANES_EXECUTE_N is set", () => {
		expect(getExecuteLaneCapacity({ SF_LANES_EXECUTE_N: "2" })).toBe(2);
	});

	it("ignores invalid values and returns default", () => {
		expect(getExecuteLaneCapacity({ SF_LANES_EXECUTE_N: "" })).toBe(1);
		expect(getExecuteLaneCapacity({ SF_LANES_EXECUTE_N: "0" })).toBe(1);
	});
});

// ── selectLaneAwareUnits ──────────────────────────────────────────────────────

describe("selectLaneAwareUnits", () => {
	const units = [
		{ unitType: "plan-slice", unitId: "A" },
		{ unitType: "execute-task", unitId: "B" },
		{ unitType: "plan-slice", unitId: "C" },
		{ unitType: "execute-task", unitId: "D" },
		{ unitType: "plan-slice", unitId: "E" },
	];

	it("selects one planning and one execute unit with default caps", () => {
		const selected = selectLaneAwareUnits(units, 1, 1);
		expect(selected).toHaveLength(2);
		expect(selected[0].unitId).toBe("A"); // first planning candidate
		expect(selected[1].unitId).toBe("B"); // first execute candidate
	});

	it("saturated execute slot does not block subsequent planning dispatch", () => {
		// Only execute cap=0 — should only pick planning candidates
		const selected = selectLaneAwareUnits(units, 1, 0);
		expect(selected).toHaveLength(1);
		expect(selected[0].unitType).toBe("plan-slice");
	});

	it("saturated planning slot does not block subsequent execute dispatch", () => {
		// Only planning cap=0 — should only pick execute candidates
		const selected = selectLaneAwareUnits(units, 0, 1);
		expect(selected).toHaveLength(1);
		expect(selected[0].unitType).toBe("execute-task");
	});

	it("selects up to planningCap=2 planning units", () => {
		const selected = selectLaneAwareUnits(units, 2, 1);
		// Should pick A (planning), B (execute), C (planning)
		expect(selected).toHaveLength(3);
		expect(selected[0].unitId).toBe("A");
		expect(selected[1].unitId).toBe("B");
		expect(selected[2].unitId).toBe("C");
	});

	it("returns empty array for empty candidate list", () => {
		const selected = selectLaneAwareUnits([], 1, 1);
		expect(selected).toHaveLength(0);
	});

	it("stops early once both caps are exhausted", () => {
		const selected = selectLaneAwareUnits(units, 1, 1);
		// Should not scan past the point where both are saturated
		expect(selected.map((u) => u.unitId)).toEqual(["A", "B"]);
	});
});
