import { afterAll, describe, expect, it } from 'vitest'
import { prisma, createCaller } from '../setup'
import {
  createTestUser,
  createTestProgram,
  createTestProject,
  createTestCompetition,
  createTestRound,
  createTestProjectRoundState,
  cleanupTestData,
  uid,
} from '../helpers'
import { userRouter } from '../../src/server/routers/user'
import type { UserRole } from '@prisma/client'

async function createUserWithRoles(primaryRole: UserRole, rolesArray: UserRole[]) {
  const id = uid('user')
  return prisma.user.create({
    data: {
      id,
      email: `${id}@test.local`,
      name: `Test ${primaryRole}`,
      role: primaryRole,
      roles: rolesArray,
      status: 'ACTIVE',
    },
  })
}

describe('user.getDefaultDashboard', () => {
  const programIds: string[] = []
  const userIds: string[] = []

  afterAll(async () => {
    for (const programId of programIds) {
      await prisma.mentorAssignment.deleteMany({ where: { project: { programId } } })
      await cleanupTestData(programId, [])
    }
    if (userIds.length > 0) {
      await prisma.user.deleteMany({ where: { id: { in: userIds } } })
    }
  })

  it('returns /admin for SUPER_ADMIN unconditionally', async () => {
    const u = await createUserWithRoles('SUPER_ADMIN', ['SUPER_ADMIN'])
    userIds.push(u.id)
    const caller = createCaller(userRouter, { id: u.id, email: u.email, role: 'SUPER_ADMIN' })
    const result = await caller.getDefaultDashboard()
    expect(result.path).toBe('/admin')
    expect(result.role).toBe('SUPER_ADMIN')
  })

  it('returns /jury for a juror with a pending assignment in an active round', async () => {
    const u = await createUserWithRoles('JURY_MEMBER', ['JURY_MEMBER', 'OBSERVER'])
    userIds.push(u.id)
    const program = await createTestProgram({ name: `default-juror-active-${uid()}` })
    programIds.push(program.id)
    const competition = await createTestCompetition(program.id, { status: 'ACTIVE' })
    const round = await createTestRound(competition.id, {
      roundType: 'EVALUATION',
      status: 'ROUND_ACTIVE',
    })
    const project = await createTestProject(program.id)
    await createTestProjectRoundState(project.id, round.id)
    await prisma.assignment.create({
      data: { userId: u.id, projectId: project.id, roundId: round.id, method: 'MANUAL' },
    })
    const caller = createCaller(userRouter, { id: u.id, email: u.email, role: 'JURY_MEMBER' })
    const result = await caller.getDefaultDashboard()
    expect(result.path).toBe('/jury')
  })

  it('falls back to /jury (static priority) when juror+observer has no active work', async () => {
    const u = await createUserWithRoles('JURY_MEMBER', ['JURY_MEMBER', 'OBSERVER'])
    userIds.push(u.id)
    const caller = createCaller(userRouter, { id: u.id, email: u.email, role: 'JURY_MEMBER' })
    const result = await caller.getDefaultDashboard()
    expect(result.path).toBe('/jury')
    expect(result.reason).toBe('static-fallback')
  })

  it('returns /mentor for a mentor+juror with active mentoring but no jury work', async () => {
    const u = await createUserWithRoles('MENTOR', ['MENTOR', 'JURY_MEMBER'])
    userIds.push(u.id)
    const program = await createTestProgram({ name: `default-mentor-active-${uid()}` })
    programIds.push(program.id)
    const competition = await createTestCompetition(program.id, { status: 'ACTIVE' })
    const round = await createTestRound(competition.id, {
      roundType: 'MENTORING',
      status: 'ROUND_ACTIVE',
    })
    const project = await createTestProject(program.id)
    await createTestProjectRoundState(project.id, round.id)
    await prisma.mentorAssignment.create({
      data: {
        projectId: project.id,
        mentorId: u.id,
        method: 'MANUAL',
        workspaceEnabled: true,
      },
    })
    const caller = createCaller(userRouter, { id: u.id, email: u.email, role: 'MENTOR' })
    const result = await caller.getDefaultDashboard()
    expect(result.path).toBe('/mentor')
  })

  it('returns /jury when both jury and mentor work are active (jury wins on priority)', async () => {
    const u = await createUserWithRoles('JURY_MEMBER', ['JURY_MEMBER', 'MENTOR'])
    userIds.push(u.id)
    const program = await createTestProgram({ name: `default-both-active-${uid()}` })
    programIds.push(program.id)
    const competition = await createTestCompetition(program.id, { status: 'ACTIVE' })
    const evalRound = await createTestRound(competition.id, {
      roundType: 'EVALUATION',
      status: 'ROUND_ACTIVE',
      sortOrder: 0,
    })
    const mentRound = await createTestRound(competition.id, {
      roundType: 'MENTORING',
      status: 'ROUND_ACTIVE',
      sortOrder: 1,
    })
    const projectE = await createTestProject(program.id)
    const projectM = await createTestProject(program.id)
    await createTestProjectRoundState(projectE.id, evalRound.id)
    await createTestProjectRoundState(projectM.id, mentRound.id)
    await prisma.assignment.create({
      data: { userId: u.id, projectId: projectE.id, roundId: evalRound.id, method: 'MANUAL' },
    })
    await prisma.mentorAssignment.create({
      data: {
        projectId: projectM.id,
        mentorId: u.id,
        method: 'MANUAL',
        workspaceEnabled: true,
      },
    })
    const caller = createCaller(userRouter, { id: u.id, email: u.email, role: 'JURY_MEMBER' })
    const result = await caller.getDefaultDashboard()
    expect(result.path).toBe('/jury')
  })

  it('returns /observer for an observer-only user (static fallback)', async () => {
    const u = await createUserWithRoles('OBSERVER', ['OBSERVER'])
    userIds.push(u.id)
    const caller = createCaller(userRouter, { id: u.id, email: u.email, role: 'OBSERVER' })
    const result = await caller.getDefaultDashboard()
    expect(result.path).toBe('/observer')
  })
})
