import { prisma } from '@/lib/prisma'
import { aiInterpretCriteria } from './ai-award-eligibility'

const BATCH_SIZE = 20

/**
 * Process eligibility for an award in the background.
 * Updates progress in the database as it goes so the frontend can poll.
 */
export async function processEligibilityJob(
  awardId: string,
  includeSubmitted: boolean,
  userId: string,
  filteringRoundId?: string
): Promise<void> {
  try {
    // Mark job as PROCESSING
    const award = await prisma.specialAward.findUniqueOrThrow({
      where: { id: awardId },
      include: { program: true },
    })

    // Rich select matching the data the integrated filtering pass sends
    const projectSelect = {
      id: true,
      title: true,
      description: true,
      competitionCategory: true,
      country: true,
      geographicZone: true,
      tags: true,
      oceanIssue: true,
      institution: true,
      foundedAt: true,
      wantsMentorship: true,
      submissionSource: true,
      submittedAt: true,
      _count: { select: { teamMembers: true, files: true } },
      files: { select: { fileType: true, size: true, pageCount: true } },
    } as const

    // Get projects — scoped to filtering round PASSED projects if provided
    let projects: Array<{
      id: string
      title: string
      description: string | null
      competitionCategory: string | null
      country: string | null
      geographicZone: string | null
      tags: string[]
      oceanIssue: string | null
      institution: string | null
      foundedAt: Date | null
      wantsMentorship: boolean
      submissionSource: string
      submittedAt: Date | null
      _count: { teamMembers: number; files: number }
      files: Array<{ fileType: string | null; size: number; pageCount: number | null }>
    }>

    if (filteringRoundId) {
      // Scope to projects that effectively PASSED filtering (including admin overrides)
      const passedResults = await prisma.filteringResult.findMany({
        where: {
          roundId: filteringRoundId,
          OR: [
            { finalOutcome: 'PASSED' },
            { finalOutcome: null, outcome: 'PASSED' },
          ],
        },
        select: { projectId: true },
      })
      const passedIds = passedResults.map((r) => r.projectId)

      if (passedIds.length === 0) {
        await prisma.specialAward.update({
          where: { id: awardId },
          data: {
            eligibilityJobStatus: 'COMPLETED',
            eligibilityJobTotal: 0,
            eligibilityJobDone: 0,
          },
        })
        return
      }

      projects = await prisma.project.findMany({
        where: {
          id: { in: passedIds },
          programId: award.programId,
        },
        select: projectSelect,
      })
    } else {
      const statusFilter = includeSubmitted
        ? (['SUBMITTED', 'ELIGIBLE', 'ASSIGNED', 'SEMIFINALIST', 'FINALIST'] as const)
        : (['ELIGIBLE', 'ASSIGNED', 'SEMIFINALIST', 'FINALIST'] as const)

      projects = await prisma.project.findMany({
        where: {
          programId: award.programId,
          status: { in: [...statusFilter] },
        },
        select: projectSelect,
      })
    }

    if (projects.length === 0) {
      await prisma.specialAward.update({
        where: { id: awardId },
        data: {
          eligibilityJobStatus: 'COMPLETED',
          eligibilityJobTotal: 0,
          eligibilityJobDone: 0,
        },
      })
      return
    }

    await prisma.specialAward.update({
      where: { id: awardId },
      data: {
        eligibilityJobStatus: 'PROCESSING',
        eligibilityJobTotal: projects.length,
        eligibilityJobDone: 0,
        eligibilityJobError: null,
        eligibilityJobStarted: new Date(),
      },
    })

    // AI interpretation (if criteria text exists AND AI eligibility is enabled)
    // Process in batches to avoid timeouts
    let aiResults: Map<string, { eligible: boolean; confidence: number; qualityScore: number; reasoning: string }> | undefined

    if (award.criteriaText && award.useAiEligibility) {
      aiResults = new Map()

      for (let i = 0; i < projects.length; i += BATCH_SIZE) {
        const batch = projects.slice(i, i + BATCH_SIZE)
        const aiEvals = await aiInterpretCriteria(award.criteriaText, batch)

        for (const e of aiEvals) {
          aiResults.set(e.projectId, {
            eligible: e.eligible,
            confidence: e.confidence,
            qualityScore: e.qualityScore,
            reasoning: e.reasoning,
          })
        }

        // Update progress
        await prisma.specialAward.update({
          where: { id: awardId },
          data: {
            eligibilityJobDone: Math.min(i + BATCH_SIZE, projects.length),
          },
        })
      }
    } else {
      // No AI needed, mark all as done
      await prisma.specialAward.update({
        where: { id: awardId },
        data: { eligibilityJobDone: projects.length },
      })
    }

    // Combine results
    const eligibilities = projects.map((project) => {
      const aiEval = aiResults?.get(project.id)
      const eligible = aiEval?.eligible ?? true
      const method = aiResults ? 'AUTO' : 'MANUAL'

      return {
        projectId: project.id,
        eligible,
        method,
        qualityScore: aiEval?.qualityScore ?? null,
        aiReasoningJson: aiEval
          ? { confidence: aiEval.confidence, qualityScore: aiEval.qualityScore, reasoning: aiEval.reasoning }
          : null,
      }
    })

    // Upsert eligibilities — preserve manual overrides and shortlist status
    await prisma.$transaction(
      eligibilities.map((e) =>
        prisma.awardEligibility.upsert({
          where: {
            awardId_projectId: {
              awardId,
              projectId: e.projectId,
            },
          },
          create: {
            awardId,
            projectId: e.projectId,
            eligible: e.eligible,
            method: e.method as 'AUTO' | 'MANUAL',
            qualityScore: e.qualityScore,
            aiReasoningJson: e.aiReasoningJson ?? undefined,
          },
          update: {
            // Only update AI-computed fields; DO NOT reset overriddenBy,
            // overriddenAt, shortlisted, confirmedAt, confirmedBy — those
            // reflect admin decisions that must survive re-runs.
            qualityScore: e.qualityScore,
            aiReasoningJson: e.aiReasoningJson ?? undefined,
          },
        })
      )
    )

    // For records without manual override, sync the eligible/method fields
    const nonOverridden = await prisma.awardEligibility.findMany({
      where: { awardId, overriddenBy: null },
      select: { projectId: true },
    })
    const nonOverriddenIds = new Set(nonOverridden.map((r) => r.projectId))

    if (nonOverriddenIds.size > 0) {
      await prisma.$transaction(
        eligibilities
          .filter((e) => nonOverriddenIds.has(e.projectId))
          .map((e) =>
            prisma.awardEligibility.update({
              where: {
                awardId_projectId: { awardId, projectId: e.projectId },
              },
              data: {
                eligible: e.eligible,
                method: e.method as 'AUTO' | 'MANUAL',
              },
            })
          )
      )
    }

    // Auto-shortlist top N eligible projects by qualityScore
    // Only auto-shortlist records that aren't already manually shortlisted
    const shortlistSize = award.shortlistSize ?? 10
    const alreadyShortlisted = await prisma.awardEligibility.findMany({
      where: { awardId, shortlisted: true, overriddenBy: { not: null } },
      select: { projectId: true },
    })
    const manuallyShortlistedIds = new Set(alreadyShortlisted.map((r) => r.projectId))

    const topEligible = eligibilities
      .filter((e) => e.eligible && e.qualityScore != null && !manuallyShortlistedIds.has(e.projectId))
      .sort((a, b) => (b.qualityScore ?? 0) - (a.qualityScore ?? 0))
      .slice(0, Math.max(0, shortlistSize - manuallyShortlistedIds.size))

    if (topEligible.length > 0) {
      await prisma.$transaction(
        topEligible.map((e) =>
          prisma.awardEligibility.update({
            where: {
              awardId_projectId: {
                awardId,
                projectId: e.projectId,
              },
            },
            data: { shortlisted: true },
          })
        )
      )
    }

    // Mark as completed
    await prisma.specialAward.update({
      where: { id: awardId },
      data: {
        eligibilityJobStatus: 'COMPLETED',
        eligibilityJobDone: projects.length,
      },
    })
  } catch (error) {
    // Mark as failed
    const errorMessage = error instanceof Error ? error.message : 'Unknown error'
    try {
      await prisma.specialAward.update({
        where: { id: awardId },
        data: {
          eligibilityJobStatus: 'FAILED',
          eligibilityJobError: errorMessage,
        },
      })
    } catch (updateErr) {
      // If we can't even update the status, log and give up
      console.error('Failed to update eligibility job status:', updateErr, 'Original error:', error)
    }
  }
}
