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'
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',
    },
  })
}

const DAY = 86_400_000

describe('mentor.getMenteeActivity', () => {
  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('classifies projects as unassigned / assigned / active / stalled and returns totals', async () => {
    const admin = await createTestUser('SUPER_ADMIN')
    userIds.push(admin.id)
    const program = await createTestProgram({ name: `mentee-activity-${uid()}` })
    programIds.push(program.id)

    const lead = await createUserWithRoles('APPLICANT', ['APPLICANT'])
    userIds.push(lead.id)
    const mentor = await createUserWithRoles('MENTOR', ['MENTOR'])
    userIds.push(mentor.id)

    // Four projects all wantsMentorship
    const pUnassigned = await createTestProject(program.id, { title: 'Unassigned' })
    const pAssigned = await createTestProject(program.id, { title: 'Assigned' })
    const pActive = await createTestProject(program.id, { title: 'Active' })
    const pStalled = await createTestProject(program.id, { title: 'Stalled' })
    for (const p of [pUnassigned, pAssigned, pActive, pStalled]) {
      await prisma.project.update({ where: { id: p.id }, data: { wantsMentorship: true } })
      await prisma.teamMember.create({
        data: { projectId: p.id, userId: lead.id, role: 'LEAD' },
      })
    }

    // Assigned: mentor assigned, no activity yet
    await prisma.mentorAssignment.create({
      data: {
        projectId: pAssigned.id,
        mentorId: mentor.id,
        method: 'MANUAL',
        assignedBy: admin.id,
        workspaceEnabled: true,
      },
    })

    // Active: mentor + recent message
    const aActive = await prisma.mentorAssignment.create({
      data: {
        projectId: pActive.id,
        mentorId: mentor.id,
        method: 'MANUAL',
        assignedBy: admin.id,
        workspaceEnabled: true,
      },
    })
    await prisma.mentorMessage.create({
      data: {
        projectId: pActive.id,
        senderId: mentor.id,
        message: 'recent ping',
        workspaceId: aActive.id,
        createdAt: new Date(Date.now() - 2 * DAY),
      },
    })

    // Stalled: mentor + last message > 14 days ago
    const aStalled = await prisma.mentorAssignment.create({
      data: {
        projectId: pStalled.id,
        mentorId: mentor.id,
        method: 'MANUAL',
        assignedBy: admin.id,
        workspaceEnabled: true,
        assignedAt: new Date(Date.now() - 30 * DAY),
      },
    })
    await prisma.mentorMessage.create({
      data: {
        projectId: pStalled.id,
        senderId: mentor.id,
        message: 'old ping',
        workspaceId: aStalled.id,
        createdAt: new Date(Date.now() - 20 * DAY),
      },
    })

    const caller = createCaller(mentorRouter, {
      id: admin.id,
      email: admin.email,
      role: 'SUPER_ADMIN',
    })
    const result = await caller.getMenteeActivity({ programId: program.id })

    const byTitle = Object.fromEntries(
      result.rows.map((r: (typeof result.rows)[number]) => [r.project.title, r]),
    )
    expect(byTitle['Unassigned'].status).toBe('unassigned')
    expect(byTitle['Unassigned'].mentor).toBeNull()
    expect(byTitle['Assigned'].status).toBe('assigned')
    expect(byTitle['Assigned'].mentor?.id).toBe(mentor.id)
    expect(byTitle['Active'].status).toBe('active')
    expect(byTitle['Active'].lastActivityAt).not.toBeNull()
    expect(byTitle['Stalled'].status).toBe('stalled')

    expect(result.totals.unassigned).toBe(1)
    expect(result.totals.assigned).toBe(1)
    expect(result.totals.active).toBe(1)
    expect(result.totals.stalled).toBe(1)

    // Team lead resolved
    expect(byTitle['Active'].teamLead?.email).toBe(lead.email)
  })

  it('only includes projects that wantMentorship within the program scope', async () => {
    const admin = await createTestUser('SUPER_ADMIN')
    userIds.push(admin.id)
    const program = await createTestProgram({ name: `mentee-scope-${uid()}` })
    programIds.push(program.id)

    const pYes = await createTestProject(program.id, { title: 'Yes' })
    const pNo = await createTestProject(program.id, { title: 'No' })
    await prisma.project.update({ where: { id: pYes.id }, data: { wantsMentorship: true } })
    await prisma.project.update({ where: { id: pNo.id }, data: { wantsMentorship: false } })

    const caller = createCaller(mentorRouter, {
      id: admin.id,
      email: admin.email,
      role: 'SUPER_ADMIN',
    })
    const result = await caller.getMenteeActivity({ programId: program.id })

    expect(
      result.rows.map((r: (typeof result.rows)[number]) => r.project.title).sort(),
    ).toEqual(['Yes'])
  })
})
