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

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

describe('mentor.dropAssignment', () => {
  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('mentor can drop their own assignment with a valid reason', async () => {
    const mentor = await createMentor()
    userIds.push(mentor.id)
    const admin = await createTestUser('SUPER_ADMIN')
    userIds.push(admin.id)
    const program = await createTestProgram({ name: `drop-ok-${uid()}` })
    programIds.push(program.id)
    const project = await createTestProject(program.id, { title: 'P', competitionCategory: 'STARTUP' })
    const ma = await prisma.mentorAssignment.create({
      data: {
        projectId: project.id,
        mentorId: mentor.id,
        method: 'MANUAL',
        assignedBy: admin.id,
        workspaceEnabled: true,
      },
    })

    const caller = createCaller(mentorRouter, {
      id: mentor.id,
      email: mentor.email,
      role: 'MENTOR',
    })
    const result = await caller.dropAssignment({
      assignmentId: ma.id,
      reason: 'Schedule conflict — cannot dedicate enough time',
    })
    expect(result.droppedAt).not.toBeNull()
    expect(result.droppedBy).toBe('mentor')
    expect(result.droppedReason).toContain('Schedule conflict')
  })

  it('rejects when reason is too short', async () => {
    const mentor = await createMentor()
    userIds.push(mentor.id)
    const admin = await createTestUser('SUPER_ADMIN')
    userIds.push(admin.id)
    const program = await createTestProgram({ name: `drop-short-${uid()}` })
    programIds.push(program.id)
    const project = await createTestProject(program.id, {
      title: 'P',
      competitionCategory: 'STARTUP',
    })
    const ma = await prisma.mentorAssignment.create({
      data: {
        projectId: project.id,
        mentorId: mentor.id,
        method: 'MANUAL',
        assignedBy: admin.id,
      },
    })
    const caller = createCaller(mentorRouter, {
      id: mentor.id,
      email: mentor.email,
      role: 'MENTOR',
    })
    await expect(
      caller.dropAssignment({ assignmentId: ma.id, reason: 'short' }),
    ).rejects.toThrow()
  })

  it('rejects when mentor does not own the assignment', async () => {
    const mentorA = await createMentor()
    const mentorB = await createMentor()
    userIds.push(mentorA.id, mentorB.id)
    const admin = await createTestUser('SUPER_ADMIN')
    userIds.push(admin.id)
    const program = await createTestProgram({ name: `drop-foreign-${uid()}` })
    programIds.push(program.id)
    const project = await createTestProject(program.id, {
      title: 'P',
      competitionCategory: 'STARTUP',
    })
    const ma = await prisma.mentorAssignment.create({
      data: {
        projectId: project.id,
        mentorId: mentorA.id,
        method: 'MANUAL',
        assignedBy: admin.id,
      },
    })
    const callerB = createCaller(mentorRouter, {
      id: mentorB.id,
      email: mentorB.email,
      role: 'MENTOR',
    })
    await expect(
      callerB.dropAssignment({
        assignmentId: ma.id,
        reason: 'Trying to steal the drop',
      }),
    ).rejects.toThrow(/not your assignment/i)
  })

  it('rejects already-dropped assignments', async () => {
    const mentor = await createMentor()
    userIds.push(mentor.id)
    const admin = await createTestUser('SUPER_ADMIN')
    userIds.push(admin.id)
    const program = await createTestProgram({ name: `drop-twice-${uid()}` })
    programIds.push(program.id)
    const project = await createTestProject(program.id, {
      title: 'P',
      competitionCategory: 'STARTUP',
    })
    const ma = await prisma.mentorAssignment.create({
      data: {
        projectId: project.id,
        mentorId: mentor.id,
        method: 'MANUAL',
        assignedBy: admin.id,
        droppedAt: new Date(),
        droppedReason: 'already dropped',
        droppedBy: 'mentor',
      },
    })
    const caller = createCaller(mentorRouter, {
      id: mentor.id,
      email: mentor.email,
      role: 'MENTOR',
    })
    await expect(
      caller.dropAssignment({
        assignmentId: ma.id,
        reason: 'Trying to drop again',
      }),
    ).rejects.toThrow(/already dropped/i)
  })

  it('rejects already-completed assignments', async () => {
    const mentor = await createMentor()
    userIds.push(mentor.id)
    const admin = await createTestUser('SUPER_ADMIN')
    userIds.push(admin.id)
    const program = await createTestProgram({ name: `drop-completed-${uid()}` })
    programIds.push(program.id)
    const project = await createTestProject(program.id, {
      title: 'P',
      competitionCategory: 'STARTUP',
    })
    const ma = await prisma.mentorAssignment.create({
      data: {
        projectId: project.id,
        mentorId: mentor.id,
        method: 'MANUAL',
        assignedBy: admin.id,
        completionStatus: 'completed',
      },
    })
    const caller = createCaller(mentorRouter, {
      id: mentor.id,
      email: mentor.email,
      role: 'MENTOR',
    })
    await expect(
      caller.dropAssignment({
        assignmentId: ma.id,
        reason: 'Already wrapped up the project',
      }),
    ).rejects.toThrow(/already completed/i)
  })
})
