/**
 * Test Data Factories
 *
 * Provides helper functions to create test data in the database.
 * Each factory returns the created record and uses unique identifiers
 * to avoid collisions between test files.
 */

import { randomUUID } from 'crypto'
import { prisma } from './setup'
import type {
  UserRole,
  RoundType,
  RoundStatus,
  CompetitionStatus,
  ProjectRoundStateValue,
  AssignmentMethod,
  EvaluationStatus,
} from '@prisma/client'

export function uid(prefix = 'test'): string {
  return `${prefix}-${randomUUID().slice(0, 12)}`
}

// ─── User Factory ──────────────────────────────────────────────────────────

export async function createTestUser(
  role: UserRole = 'JURY_MEMBER',
  overrides: Partial<{
    email: string
    name: string
    status: string
    expertiseTags: string[]
    maxAssignments: number
    country: string
  }> = {},
) {
  const id = uid('user')
  return prisma.user.create({
    data: {
      id,
      email: overrides.email ?? `${id}@test.local`,
      name: overrides.name ?? `Test ${role}`,
      role,
      status: (overrides.status as any) ?? 'ACTIVE',
      expertiseTags: overrides.expertiseTags ?? [],
      maxAssignments: overrides.maxAssignments ?? null,
      country: overrides.country ?? null,
    },
  })
}

// ─── Program Factory ───────────────────────────────────────────────────────

export async function createTestProgram(
  overrides: Partial<{ name: string; year: number; defaultAttendeeCap: number }> = {},
) {
  const id = uid('prog')
  return prisma.program.create({
    data: {
      id,
      name: overrides.name ?? `Test Program ${id}`,
      year: overrides.year ?? 2026,
      status: 'ACTIVE',
      ...(overrides.defaultAttendeeCap !== undefined
        ? { defaultAttendeeCap: overrides.defaultAttendeeCap }
        : {}),
    },
  })
}

// ─── Competition Factory ───────────────────────────────────────────────────

export async function createTestCompetition(
  programId: string,
  overrides: Partial<{
    name: string
    slug: string
    status: CompetitionStatus
  }> = {},
) {
  const id = uid('comp')
  return prisma.competition.create({
    data: {
      id,
      programId,
      name: overrides.name ?? `Competition ${id}`,
      slug: overrides.slug ?? id,
      status: overrides.status ?? 'DRAFT',
    },
  })
}

// ─── Round Factory ─────────────────────────────────────────────────────────

export async function createTestRound(
  competitionId: string,
  overrides: Partial<{
    name: string
    slug: string
    roundType: RoundType
    status: RoundStatus
    sortOrder: number
    configJson: Record<string, unknown>
    windowOpenAt: Date
    windowCloseAt: Date
  }> = {},
) {
  const id = uid('round')
  return prisma.round.create({
    data: {
      id,
      competitionId,
      name: overrides.name ?? `Round ${id}`,
      slug: overrides.slug ?? id,
      roundType: overrides.roundType ?? 'EVALUATION',
      status: overrides.status ?? 'ROUND_ACTIVE',
      sortOrder: overrides.sortOrder ?? 0,
      configJson: (overrides.configJson as any) ?? undefined,
      windowOpenAt: overrides.windowOpenAt ?? null,
      windowCloseAt: overrides.windowCloseAt ?? null,
    },
  })
}

// ─── Project Factory ───────────────────────────────────────────────────────

export async function createTestProject(
  programId: string,
  overrides: Partial<{
    title: string
    description: string
    country: string
    tags: string[]
    competitionCategory: string
    oceanIssue: string
  }> = {},
) {
  const id = uid('proj')
  return prisma.project.create({
    data: {
      id,
      programId,
      title: overrides.title ?? `Test Project ${id}`,
      description: overrides.description ?? 'Test project description',
      country: overrides.country ?? 'France',
      tags: overrides.tags ?? [],
      competitionCategory: (overrides.competitionCategory as any) ?? null,
      oceanIssue: (overrides.oceanIssue as any) ?? null,
    },
  })
}

// ─── ProjectRoundState Factory ─────────────────────────────────────────────

export async function createTestProjectRoundState(
  projectId: string,
  roundId: string,
  overrides: Partial<{
    state: ProjectRoundStateValue
    exitedAt: Date | null
  }> = {},
) {
  return prisma.projectRoundState.create({
    data: {
      projectId,
      roundId,
      state: overrides.state ?? 'PENDING',
      exitedAt: overrides.exitedAt ?? null,
    },
  })
}

// ─── Assignment Factory ────────────────────────────────────────────────────

export async function createTestAssignment(
  userId: string,
  projectId: string,
  roundId: string,
  overrides: Partial<{
    method: AssignmentMethod
    isCompleted: boolean
    juryGroupId: string
  }> = {},
) {
  return prisma.assignment.create({
    data: {
      userId,
      projectId,
      roundId,
      method: overrides.method ?? 'MANUAL',
      isCompleted: overrides.isCompleted ?? false,
      juryGroupId: overrides.juryGroupId ?? undefined,
    },
  })
}

// ─── Evaluation Factory ───────────────────────────────────────────────────

export async function createTestEvaluation(
  assignmentId: string,
  formId: string,
  overrides: Partial<{
    status: 'NOT_STARTED' | 'DRAFT' | 'SUBMITTED' | 'LOCKED'
    globalScore: number
    submittedAt: Date
  }> = {},
) {
  return prisma.evaluation.create({
    data: {
      assignmentId,
      formId,
      status: overrides.status ?? 'NOT_STARTED',
      globalScore: overrides.globalScore ?? null,
      submittedAt: overrides.submittedAt ?? null,
    },
  })
}

// ─── Evaluation Form Factory ───────────────────────────────────────────────

export async function createTestEvaluationForm(
  roundId: string,
  criteria: Array<{
    id: string
    label: string
    scale: string
    weight: number
  }> = [],
) {
  return prisma.evaluationForm.create({
    data: {
      roundId,
      criteriaJson: criteria.length > 0
        ? criteria
        : [
            { id: 'c1', label: 'Innovation', scale: '1-10', weight: 1 },
            { id: 'c2', label: 'Impact', scale: '1-10', weight: 1 },
          ],
      isActive: true,
    },
  })
}


// ─── Filtering Rule Factory ────────────────────────────────────────────────

export async function createTestFilteringRule(
  roundId: string,
  overrides: Partial<{
    name: string
    ruleType: string
    configJson: Record<string, unknown>
    priority: number
  }> = {},
) {
  return prisma.filteringRule.create({
    data: {
      roundId,
      name: overrides.name ?? 'Test Filter Rule',
      ruleType: (overrides.ruleType as any) ?? 'DOCUMENT_CHECK',
      configJson: (overrides.configJson ?? { requiredFileTypes: ['EXEC_SUMMARY'], action: 'REJECT' }) as any,
      priority: overrides.priority ?? 0,
      isActive: true,
    },
  })
}

// ─── COI Factory ───────────────────────────────────────────────────────────

export async function createTestCOI(
  assignmentId: string,
  userId: string,
  projectId: string,
  hasConflict = true,
) {
  return prisma.conflictOfInterest.create({
    data: {
      assignmentId,
      userId,
      projectId,
      hasConflict,
      conflictType: hasConflict ? 'personal' : null,
      description: hasConflict ? 'Test conflict' : null,
    },
  })
}

// ─── Cohort + CohortProject Factory ────────────────────────────────────────

export async function createTestCohort(
  roundId: string,
  overrides: Partial<{
    name: string
    isOpen: boolean
    votingMode: string
  }> = {},
) {
  const id = uid('cohort')
  return prisma.cohort.create({
    data: {
      id,
      roundId,
      name: overrides.name ?? `Cohort ${id}`,
      isOpen: overrides.isOpen ?? false,
      votingMode: overrides.votingMode ?? 'simple',
    },
  })
}

export async function createTestCohortProject(
  cohortId: string,
  projectId: string,
  sortOrder = 0,
) {
  return prisma.cohortProject.create({
    data: {
      cohortId,
      projectId,
      sortOrder,
    },
  })
}

// ─── Cleanup Utility ───────────────────────────────────────────────────────

/**
 * Cleanup all test data created by a specific test run.
 * Pass the programId to cascade-delete most related data.
 */
export async function cleanupTestData(programId: string, userIds: string[] = []) {
  // Delete in reverse dependency order — scoped by programId or userIds
  if (userIds.length > 0) {
    await prisma.decisionAuditLog.deleteMany({ where: { actorId: { in: userIds } } })
    await prisma.auditLog.deleteMany({ where: { userId: { in: userIds } } })
  }
  // Competition/Round cascade cleanup
  await prisma.cohortProject.deleteMany({ where: { cohort: { round: { competition: { programId } } } } })
  await prisma.cohort.deleteMany({ where: { round: { competition: { programId } } } })
  await prisma.liveProgressCursor.deleteMany({ where: { round: { competition: { programId } } } })
  await prisma.filteringResult.deleteMany({ where: { round: { competition: { programId } } } })
  await prisma.filteringRule.deleteMany({ where: { round: { competition: { programId } } } })
  await prisma.filteringJob.deleteMany({ where: { round: { competition: { programId } } } })
  await prisma.assignmentJob.deleteMany({ where: { round: { competition: { programId } } } })
  await prisma.conflictOfInterest.deleteMany({ where: { assignment: { round: { competition: { programId } } } } })
  await prisma.evaluation.deleteMany({ where: { assignment: { round: { competition: { programId } } } } })
  await prisma.assignment.deleteMany({ where: { round: { competition: { programId } } } })
  await prisma.evaluationForm.deleteMany({ where: { round: { competition: { programId } } } })
  await prisma.fileRequirement.deleteMany({ where: { round: { competition: { programId } } } })
  await prisma.gracePeriod.deleteMany({ where: { round: { competition: { programId } } } })
  await prisma.reminderLog.deleteMany({ where: { round: { competition: { programId } } } })
  await prisma.evaluationSummary.deleteMany({ where: { round: { competition: { programId } } } })
  await prisma.evaluationDiscussion.deleteMany({ where: { round: { competition: { programId } } } })
  await prisma.projectRoundState.deleteMany({ where: { round: { competition: { programId } } } })
  await prisma.awardEligibility.deleteMany({ where: { award: { program: { id: programId } } } })
  await prisma.awardVote.deleteMany({ where: { award: { program: { id: programId } } } })
  await prisma.awardJuror.deleteMany({ where: { award: { program: { id: programId } } } })
  await prisma.specialAward.deleteMany({ where: { programId } })
  await prisma.round.deleteMany({ where: { competition: { programId } } })
  await prisma.competition.deleteMany({ where: { programId } })
  await prisma.projectStatusHistory.deleteMany({ where: { project: { programId } } })
  await prisma.projectFile.deleteMany({ where: { project: { programId } } })
  await prisma.projectTag.deleteMany({ where: { project: { programId } } })
  await prisma.project.deleteMany({ where: { programId } })
  await prisma.program.deleteMany({ where: { id: programId } })

  if (userIds.length > 0) {
    await prisma.user.deleteMany({ where: { id: { in: userIds } } })
  }
}
