/* @vitest-environment node */

import { describe, it, expect } from "vitest";
import {
	canAccessBranch,
	filterBranchesForSession,
	canManageUsers,
	requireUserManagement,
} from "./permissions.js";

describe("lib/auth/permissions", () => {
	describe("canAccessBranch", () => {
		it("returns false when session is missing", () => {
			expect(canAccessBranch(null, "NL01")).toBe(false);
		});

		it("returns false when branchId is missing", () => {
			expect(canAccessBranch({ role: "admin" }, "")).toBe(false);
			expect(canAccessBranch({ role: "admin" }, null)).toBe(false);
			expect(canAccessBranch({ role: "admin" }, undefined)).toBe(false);
		});

		it("allows branch role only for its own branch", () => {
			const session = { role: "branch", branchId: "NL01" };
			expect(canAccessBranch(session, "NL01")).toBe(true);
			expect(canAccessBranch(session, "NL02")).toBe(false);
		});

		it("allows admin role for any branch", () => {
			const session = { role: "admin" };
			expect(canAccessBranch(session, "NL01")).toBe(true);
			expect(canAccessBranch(session, "NL99")).toBe(true);
		});

		it("allows superadmin role for any branch", () => {
			const session = { role: "superadmin" };
			expect(canAccessBranch(session, "NL01")).toBe(true);
			expect(canAccessBranch(session, "NL99")).toBe(true);
		});

		it("allows dev role for any branch", () => {
			const session = { role: "dev" };
			expect(canAccessBranch(session, "NL01")).toBe(true);
			expect(canAccessBranch(session, "NL99")).toBe(true);
		});

		it("denies unknown roles", () => {
			const session = { role: "user", branchId: "NL01" };
			expect(canAccessBranch(session, "NL01")).toBe(false);
		});
	});

	describe("filterBranchesForSession", () => {
		it("returns [] when session is missing", () => {
			expect(filterBranchesForSession(null, ["NL01", "NL02"])).toEqual([]);
		});

		it("returns [] when branchIds is not an array", () => {
			expect(filterBranchesForSession({ role: "admin" }, null)).toEqual([]);
			expect(filterBranchesForSession({ role: "admin" }, "NL01")).toEqual([]);
		});

		it("for branch role: returns only own branch (if present)", () => {
			const session = { role: "branch", branchId: "NL01" };
			expect(filterBranchesForSession(session, ["NL01", "NL02"])).toEqual([
				"NL01",
			]);
			expect(filterBranchesForSession(session, ["NL02", "NL03"])).toEqual([]);
		});

		it("for admin/superadmin/dev: returns the full list", () => {
			const branches = ["NL01", "NL02", "NL03"];
			expect(filterBranchesForSession({ role: "admin" }, branches)).toEqual(
				branches,
			);
			expect(
				filterBranchesForSession({ role: "superadmin" }, branches),
			).toEqual(branches);
			expect(filterBranchesForSession({ role: "dev" }, branches)).toEqual(
				branches,
			);
		});

		it("does not mutate the input array", () => {
			const branches = ["NL01", "NL02"];
			const copy = [...branches];
			filterBranchesForSession({ role: "admin" }, branches);
			expect(branches).toEqual(copy);
		});
	});

	describe("canManageUsers", () => {
		it("returns true for dev and superadmin", () => {
			expect(canManageUsers({ role: "dev" })).toBe(true);
			expect(canManageUsers({ role: "superadmin" })).toBe(true);
		});

		it("returns false for admin and branch", () => {
			expect(canManageUsers({ role: "admin" })).toBe(false);
			expect(canManageUsers({ role: "branch", branchId: "NL01" })).toBe(false);
		});

		it("returns false for unknown roles or missing session", () => {
			expect(canManageUsers({ role: "user" })).toBe(false);
			expect(canManageUsers(null)).toBe(false);
		});
	});

	describe("requireUserManagement", () => {
		it("does not throw for dev and superadmin", () => {
			expect(() => requireUserManagement({ role: "dev" })).not.toThrow();
			expect(() => requireUserManagement({ role: "superadmin" })).not.toThrow();
		});

		it("throws 403 AUTH_FORBIDDEN_USER_MANAGEMENT for admin", () => {
			try {
				requireUserManagement({ role: "admin" });
				throw new Error("Expected requireUserManagement to throw");
			} catch (err) {
				expect(err).toMatchObject({
					status: 403,
					code: "AUTH_FORBIDDEN_USER_MANAGEMENT",
					message: "Forbidden",
				});
			}
		});

		it("throws 403 AUTH_FORBIDDEN_USER_MANAGEMENT for branch", () => {
			try {
				requireUserManagement({ role: "branch", branchId: "NL01" });
				throw new Error("Expected requireUserManagement to throw");
			} catch (err) {
				expect(err).toMatchObject({
					status: 403,
					code: "AUTH_FORBIDDEN_USER_MANAGEMENT",
					message: "Forbidden",
				});
			}
		});
	});
});
