import fs from "node:fs"
import path from "node:path"
import { expect, test } from "@playwright/test"

const appRoot = path.resolve(__dirname, "../../src/app")
const publicRoutes = new Set(["/", "/login", "/register"])

const toRoute = (filePath: string) => {
  const relative = path.relative(appRoot, filePath).replaceAll("\\", "/")
  const segments = relative
    .split("/")
    .slice(0, -1)
    .filter((segment) => !segment.startsWith("("))
  if (segments.some((segment) => segment.startsWith("["))) return null
  if (segments.length === 0) return "/"
  return `/${segments.join("/")}`
}

const collectPageFiles = (dir: string): string[] => {
  const entries = fs.readdirSync(dir, { withFileTypes: true })
  return entries.flatMap((entry) => {
    const fullPath = path.join(dir, entry.name)
    if (entry.isDirectory()) return collectPageFiles(fullPath)
    return entry.name === "page.tsx" ? [fullPath] : []
  })
}

const allStaticRoutes = Array.from(
  new Set(
    collectPageFiles(appRoot)
      .map((file) => toRoute(file))
      .filter((route): route is string => Boolean(route)),
  ),
).sort((a, b) => a.localeCompare(b))

const protectedRoutes = allStaticRoutes.filter((route) => !publicRoutes.has(route))

test.describe("full route regression", () => {
  test("route inventory is complete", async () => {
    expect(allStaticRoutes.length).toBeGreaterThanOrEqual(30)
    expect(allStaticRoutes).toContain("/admin/dashboard")
    expect(allStaticRoutes).toContain("/teacher/dashboard")
    expect(allStaticRoutes).toContain("/student/dashboard")
    expect(allStaticRoutes).toContain("/parent/dashboard")
    expect(allStaticRoutes).toContain("/settings")
    expect(allStaticRoutes).toContain("/profile")
  })

  for (const route of publicRoutes) {
    test(`public route renders: ${route}`, async ({ page }) => {
      const response = await page.goto(route)
      expect(response?.status() ?? 200).toBeLessThan(500)
      await expect(page).not.toHaveURL(/\/500(?:$|[/?#])/)
    })
  }

  for (const route of protectedRoutes) {
    test(`protected route guard: ${route}`, async ({ page }) => {
      const response = await page.goto(route)
      expect(response?.status() ?? 200).toBeLessThan(500)

      const finalUrl = new URL(page.url())
      const finalPath = finalUrl.pathname
      expect(finalPath === route || finalPath === "/login").toBe(true)

      if (finalPath === "/login") {
        const callbackUrl = finalUrl.searchParams.get("callbackUrl") ?? ""
        const normalizedCallback = callbackUrl.startsWith("http")
          ? new URL(callbackUrl).pathname
          : callbackUrl
        expect(normalizedCallback === "" || normalizedCallback === route).toBe(true)
      }
    })
  }
})
