import { describe, expect, it, vi } from "vitest"

const { getTokenMock } = vi.hoisted(() => ({
  getTokenMock: vi.fn(),
}))

vi.mock("next-auth/jwt", () => ({
  getToken: getTokenMock,
}))

import { middleware } from "@/proxy"

const createRequest = (pathname: string) => ({
  nextUrl: {
    pathname,
    clone: () => new URL(`http://localhost${pathname}`),
  },
  url: `http://localhost${pathname}`,
})

describe("proxy route guard", () => {
  it("redirects unauthenticated requests to login with callback", async () => {
    getTokenMock.mockResolvedValue(null)
    const response = await middleware(createRequest("/teacher/dashboard") as never)
    expect(response.status).toBe(307)
    const location = response.headers.get("location") ?? ""
    expect(location).toContain("/login")
    expect(location).toContain("callbackUrl=")
    expect(decodeURIComponent(location)).toContain("/teacher/dashboard")
  })

  it("redirects user without school:manage permission away from admin routes", async () => {
    getTokenMock.mockResolvedValue({
      permissions: ["homework:submit"],
      roles: ["student"],
    })
    const response = await middleware(createRequest("/admin/dashboard") as never)
    expect(response.status).toBe(307)
    expect(response.headers.get("location")).toContain("/student/dashboard")
  })

  it("redirects user without grade:manage permission away from management routes", async () => {
    getTokenMock.mockResolvedValue({
      permissions: ["exam:read"],
      roles: ["parent"],
    })
    const response = await middleware(createRequest("/management/grade/insights") as never)
    expect(response.status).toBe(307)
    expect(response.headers.get("location")).toContain("/parent/dashboard")
  })

  it("allows user with grade:manage permission to access management routes", async () => {
    getTokenMock.mockResolvedValue({
      permissions: ["exam:read", "grade:manage"],
      roles: ["teacher"],
    })
    const response = await middleware(createRequest("/management/grade/insights") as never)
    expect(response.status).toBe(200)
    expect(response.headers.get("location")).toBeNull()
  })
})
