import { afterAll, describe, expect, it } from 'vitest'
import { prisma, createCaller } from '../setup'
import {
  createTestProgram,
  createTestProject,
  cleanupTestData,
  uid,
} from '../helpers'
import { applicantRouter } from '../../src/server/routers/applicant'

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

async function setupMemberWithVisa(opts: {
  programName: string
  visible: boolean
  hasVisaApp: boolean
}) {
  const program = await createTestProgram({
    name: opts.programName,
    defaultAttendeeCap: 3,
  })
  await prisma.program.update({
    where: { id: program.id },
    data: { visaStatusVisibleToMembers: opts.visible },
  })
  const project = await createTestProject(program.id, {
    title: 'P',
    competitionCategory: 'STARTUP',
  })
  const user = await createApplicant()
  await prisma.teamMember.create({
    data: { projectId: project.id, userId: user.id, role: 'LEAD' },
  })
  const confirmation = await prisma.finalistConfirmation.create({
    data: {
      projectId: project.id,
      category: 'STARTUP',
      status: 'CONFIRMED',
      deadline: new Date(Date.now() + 86_400_000),
      token: `tok_${uid()}`,
      confirmedAt: new Date(),
    },
  })
  const attendee = await prisma.attendingMember.create({
    data: { confirmationId: confirmation.id, userId: user.id, needsVisa: opts.hasVisaApp },
  })
  if (opts.hasVisaApp) {
    await prisma.visaApplication.create({
      data: {
        attendingMemberId: attendee.id,
        status: 'APPOINTMENT_BOOKED',
        appointmentAt: new Date('2026-06-15T10:00:00Z'),
      },
    })
  }
  return { program, project, user }
}

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

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

  it('returns the caller-team visa apps when toggle is true', async () => {
    const { program, user } = await setupMemberWithVisa({
      programName: `visa-vis-on-${uid()}`,
      visible: true,
      hasVisaApp: true,
    })
    programIds.push(program.id)
    userIds.push(user.id)

    const caller = createCaller(applicantRouter, {
      id: user.id,
      email: user.email,
      role: 'APPLICANT',
    })
    const result = await caller.getMyVisaApplications()
    expect(Array.isArray(result)).toBe(true)
    expect(result).toHaveLength(1)
    expect(result![0].status).toBe('APPOINTMENT_BOOKED')
  })

  it('returns null when toggle is false', async () => {
    const { program, user } = await setupMemberWithVisa({
      programName: `visa-vis-off-${uid()}`,
      visible: false,
      hasVisaApp: true,
    })
    programIds.push(program.id)
    userIds.push(user.id)

    const caller = createCaller(applicantRouter, {
      id: user.id,
      email: user.email,
      role: 'APPLICANT',
    })
    const result = await caller.getMyVisaApplications()
    expect(result).toBeNull()
  })

  it('returns empty array when caller has no visa apps but toggle is on', async () => {
    const { program, user } = await setupMemberWithVisa({
      programName: `visa-vis-empty-${uid()}`,
      visible: true,
      hasVisaApp: false,
    })
    programIds.push(program.id)
    userIds.push(user.id)

    const caller = createCaller(applicantRouter, {
      id: user.id,
      email: user.email,
      role: 'APPLICANT',
    })
    const result = await caller.getMyVisaApplications()
    expect(result).toEqual([])
  })
})
