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

describe('user.getOnboardingContext — preferences filter excludes LIVE_FINAL/DELIBERATION-only groups', () => {
  let programId: string
  let competitionId: string
  let juror: { id: string; email: string; role: 'JURY_MEMBER' }
  let observerOnlyGroupId: string
  let reviewGroupId: string
  let mixedGroupId: string
  const userIds: string[] = []

  beforeAll(async () => {
    const program = await createTestProgram({ name: `prefs-filter-${uid()}` })
    programId = program.id
    const competition = await createTestCompetition(programId)
    competitionId = competition.id

    const reviewRound = await createTestRound(competitionId, {
      name: 'Review Round', slug: `review-${uid()}`, roundType: 'EVALUATION', sortOrder: 0,
    })
    const liveFinalRound = await createTestRound(competitionId, {
      name: 'Final Round', slug: `final-${uid()}`, roundType: 'LIVE_FINAL', sortOrder: 1,
    })
    const deliberationRound = await createTestRound(competitionId, {
      name: 'Delib Round', slug: `delib-${uid()}`, roundType: 'DELIBERATION', sortOrder: 2,
    })

    const reviewOnlyGroup = await prisma.juryGroup.create({
      data: {
        id: uid('jg-rev'), competitionId, name: 'Review Only Group',
        slug: uid('rev'), defaultMaxAssignments: 30,
      },
    })
    reviewGroupId = reviewOnlyGroup.id
    const liveFinalOnlyGroup = await prisma.juryGroup.create({
      data: {
        id: uid('jg-fin'), competitionId, name: 'Finals Only Group',
        slug: uid('fin'), defaultMaxAssignments: 10,
      },
    })
    observerOnlyGroupId = liveFinalOnlyGroup.id
    const mixedGroup = await prisma.juryGroup.create({
      data: {
        id: uid('jg-mix'), competitionId, name: 'Mixed Group',
        slug: uid('mix'), defaultMaxAssignments: 20,
      },
    })
    mixedGroupId = mixedGroup.id

    await prisma.round.update({ where: { id: reviewRound.id }, data: { juryGroupId: reviewOnlyGroup.id } })
    await prisma.round.update({ where: { id: liveFinalRound.id }, data: { juryGroupId: liveFinalOnlyGroup.id } })
    const mixedReview = await createTestRound(competitionId, {
      name: 'Mixed Review', slug: `mixed-rev-${uid()}`, roundType: 'EVALUATION', sortOrder: 3,
    })
    const mixedFinal = await createTestRound(competitionId, {
      name: 'Mixed Final', slug: `mixed-fin-${uid()}`, roundType: 'LIVE_FINAL', sortOrder: 4,
    })
    await prisma.round.update({ where: { id: mixedReview.id }, data: { juryGroupId: mixedGroup.id } })
    await prisma.round.update({ where: { id: mixedFinal.id }, data: { juryGroupId: mixedGroup.id } })

    void deliberationRound // referenced for cleanup; not attached to a group in these scenarios

    const u = await createTestUser('JURY_MEMBER')
    userIds.push(u.id)
    juror = { id: u.id, email: u.email, role: 'JURY_MEMBER' }

    await prisma.juryGroupMember.createMany({
      data: [
        { id: uid('jgm-rev'), juryGroupId: reviewGroupId, userId: u.id, role: 'MEMBER' },
        { id: uid('jgm-fin'), juryGroupId: observerOnlyGroupId, userId: u.id, role: 'MEMBER' },
        { id: uid('jgm-mix'), juryGroupId: mixedGroupId, userId: u.id, role: 'MEMBER' },
      ],
    })
  })

  afterAll(async () => {
    await cleanupTestData(programId, userIds)
  })

  it('returns the review-only group membership', async () => {
    const caller = createCaller(userRouter, juror)
    const ctx = await caller.getOnboardingContext()
    const names = ctx.memberships.map((m: { juryGroupName: string }) => m.juryGroupName).sort()
    expect(names).toContain('Review Only Group')
  })

  it('omits the LIVE_FINAL-only group membership', async () => {
    const caller = createCaller(userRouter, juror)
    const ctx = await caller.getOnboardingContext()
    const names = ctx.memberships.map((m: { juryGroupName: string }) => m.juryGroupName)
    expect(names).not.toContain('Finals Only Group')
  })

  it('keeps the mixed group (has at least one review round)', async () => {
    const caller = createCaller(userRouter, juror)
    const ctx = await caller.getOnboardingContext()
    const names = ctx.memberships.map((m: { juryGroupName: string }) => m.juryGroupName)
    expect(names).toContain('Mixed Group')
  })

  it('returns hasSelfServiceOptions=true when at least one membership remains', async () => {
    const caller = createCaller(userRouter, juror)
    const ctx = await caller.getOnboardingContext()
    expect(ctx.hasSelfServiceOptions).toBe(true)
    expect(ctx.memberships.length).toBe(2)
  })
})

describe('user.getOnboardingContext — juror with only LIVE_FINAL membership', () => {
  let programId: string
  let juror: { id: string; email: string; role: 'JURY_MEMBER' }
  const userIds: string[] = []

  beforeAll(async () => {
    const program = await createTestProgram({ name: `prefs-only-fin-${uid()}` })
    programId = program.id
    const competition = await createTestCompetition(programId)
    const liveFinalRound = await createTestRound(competition.id, {
      name: 'Solo Final', slug: `solo-fin-${uid()}`, roundType: 'LIVE_FINAL', sortOrder: 0,
    })
    const liveFinalOnlyGroup = await prisma.juryGroup.create({
      data: {
        id: uid('jg-only-fin'), competitionId: competition.id, name: 'Solo Finals Group',
        slug: uid('solo-fin'), defaultMaxAssignments: 10,
      },
    })
    await prisma.round.update({ where: { id: liveFinalRound.id }, data: { juryGroupId: liveFinalOnlyGroup.id } })

    const u = await createTestUser('JURY_MEMBER')
    userIds.push(u.id)
    juror = { id: u.id, email: u.email, role: 'JURY_MEMBER' }
    await prisma.juryGroupMember.create({
      data: { id: uid('jgm-only-fin'), juryGroupId: liveFinalOnlyGroup.id, userId: u.id, role: 'MEMBER' },
    })
  })

  afterAll(async () => {
    await cleanupTestData(programId, userIds)
  })

  it('returns no memberships and hasSelfServiceOptions=false', async () => {
    const caller = createCaller(userRouter, juror)
    const ctx = await caller.getOnboardingContext()
    expect(ctx.memberships).toEqual([])
    expect(ctx.hasSelfServiceOptions).toBe(false)
  })
})
