/**
 * Unit tests for redirect rules defined in next.config.ts (tickets #51, #52).
 *
 * next.config.ts exports a NextConfig object whose `redirects` method returns
 * a plain array — no Next.js runtime required. We import the raw config object
 * via dynamic require so we can inspect the redirect array without spinning up
 * the server.
 */
import { describe, expect, it } from "vitest";

// next.config.ts calls `require("@sentry/nextjs")` only in production.
// In the test environment NODE_ENV === "test", so the Sentry branch is skipped
// and the raw nextConfig is exported directly.

// We cannot import next.config.ts directly through the standard path alias
// because it lives outside `src/`. Instead we resolve it relative to the
// package root. Vitest runs from the package directory.
const config: import("next").NextConfig = (await import("../../next.config.js")).default;

describe("next.config redirects", () => {
  it("redirects /login → /auth/signin (permanent)", async () => {
    const redirects = await config.redirects!();

    const loginRedirect = redirects.find((r) => r.source === "/login");

    expect(loginRedirect, "redirect for /login must exist").toBeDefined();
    expect(loginRedirect!.destination).toBe("/auth/signin");
    expect(loginRedirect!.permanent).toBe(true);
  });

  it("redirects /blueprints → /admin/blueprints (permanent)", async () => {
    const redirects = await config.redirects!();

    const blueprintsRedirect = redirects.find((r) => r.source === "/blueprints");

    expect(blueprintsRedirect, "redirect for /blueprints must exist").toBeDefined();
    expect(blueprintsRedirect!.destination).toBe("/admin/blueprints");
    expect(blueprintsRedirect!.permanent).toBe(true);
  });

  it("does not accidentally redirect /auth/signin itself", async () => {
    const redirects = await config.redirects!();

    const signinRedirect = redirects.find((r) => r.source === "/auth/signin");
    expect(signinRedirect).toBeUndefined();
  });
});

// ─── Demand summary filter logic (#66) ────────────────────────────────────────
//
// The project detail page filters demands with:
//   demand.status !== "CANCELLED" && demand.status !== "COMPLETED"
//
// This is the business rule that ensures COMPLETED demands are excluded from
// the "open demand" count. We test the filter expression directly to guard
// against regressions (e.g., someone removing "COMPLETED" from the condition).

describe("project detail demand summary filter (ticket #66)", () => {
  type Demand = { status: string; requestedHeadcount: number; unfilledHeadcount: number };

  function calcActiveDemands(demands: Demand[]) {
    return demands.filter(
      (d) => d.status !== "CANCELLED" && d.status !== "COMPLETED",
    );
  }

  it("includes OPEN demands in the active set", () => {
    const demands: Demand[] = [{ status: "OPEN", requestedHeadcount: 2, unfilledHeadcount: 2 }];
    expect(calcActiveDemands(demands)).toHaveLength(1);
  });

  it("includes PARTIAL demands in the active set", () => {
    const demands: Demand[] = [{ status: "PARTIAL", requestedHeadcount: 2, unfilledHeadcount: 1 }];
    expect(calcActiveDemands(demands)).toHaveLength(1);
  });

  it("excludes CANCELLED demands from the active set", () => {
    const demands: Demand[] = [{ status: "CANCELLED", requestedHeadcount: 1, unfilledHeadcount: 1 }];
    expect(calcActiveDemands(demands)).toHaveLength(0);
  });

  it("excludes COMPLETED demands from the active set (regression guard for #66)", () => {
    const demands: Demand[] = [{ status: "COMPLETED", requestedHeadcount: 1, unfilledHeadcount: 0 }];
    expect(calcActiveDemands(demands)).toHaveLength(0);
  });

  it("correctly partitions a mixed demand list", () => {
    const demands: Demand[] = [
      { status: "OPEN", requestedHeadcount: 2, unfilledHeadcount: 2 },
      { status: "PARTIAL", requestedHeadcount: 3, unfilledHeadcount: 1 },
      { status: "CANCELLED", requestedHeadcount: 1, unfilledHeadcount: 1 },
      { status: "COMPLETED", requestedHeadcount: 2, unfilledHeadcount: 0 },
    ];

    const active = calcActiveDemands(demands);
    expect(active).toHaveLength(2);
    expect(active.map((d) => d.status)).toEqual(["OPEN", "PARTIAL"]);

    const totalRequested = active.reduce((s, d) => s + d.requestedHeadcount, 0);
    const totalUnfilled = active.reduce((s, d) => s + d.unfilledHeadcount, 0);
    expect(totalRequested).toBe(5);
    expect(totalUnfilled).toBe(3);
  });
});
