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

const mocks = vi.hoisted(() => {
  const whereMock = vi.fn()
  const innerJoinMock = vi.fn(() => ({ where: whereMock }))
  const fromMock = vi.fn(() => ({ innerJoin: innerJoinMock }))
  const selectMock = vi.fn(() => ({ from: fromMock }))
  return {
    authMock: vi.fn(),
    findFirstMock: vi.fn(),
    whereMock,
    selectMock,
  }
})

vi.mock("@/auth", () => ({
  auth: mocks.authMock,
}))

vi.mock("@/shared/db", () => ({
  db: {
    query: {
      users: {
        findFirst: mocks.findFirstMock,
      },
    },
    select: mocks.selectMock,
  },
}))

vi.mock("@/shared/db/schema", () => ({
  roles: { name: "name", id: "id" },
  users: { id: "id" },
  usersToRoles: { roleId: "roleId", userId: "userId" },
}))

import { GET } from "@/app/api/onboarding/status/route"

describe("GET /api/onboarding/status", () => {
  beforeEach(() => {
    vi.resetAllMocks()
  })

  it("returns not required when user is unauthenticated", async () => {
    mocks.authMock.mockResolvedValue(null)

    const response = await GET()
    const data = await response.json()

    expect(response.status).toBe(200)
    expect(data).toEqual({ required: false })
    expect(mocks.findFirstMock).not.toHaveBeenCalled()
  })

  it("returns teacher role for grade head and requires onboarding when missing onboardedAt", async () => {
    mocks.authMock.mockResolvedValue({ user: { id: "u_1" } })
    mocks.findFirstMock.mockResolvedValue({ onboardedAt: null })
    mocks.whereMock.mockResolvedValue([{ name: "grade_head" }])

    const response = await GET()
    const data = await response.json()

    expect(response.status).toBe(200)
    expect(data).toEqual({ required: true, role: "teacher" })
  })

  it("prioritizes admin role and marks not required when onboarded", async () => {
    mocks.authMock.mockResolvedValue({ user: { id: "u_2" } })
    mocks.findFirstMock.mockResolvedValue({ onboardedAt: new Date("2026-01-01") })
    mocks.whereMock.mockResolvedValue([{ name: "student" }, { name: "admin" }])

    const response = await GET()
    const data = await response.json()

    expect(response.status).toBe(200)
    expect(data).toEqual({ required: false, role: "admin" })
  })
})
