import { prisma } from '@/lib/prisma'
import {
  applyAutoTagRules,
  aiInterpretCriteria,
  type AutoTagRule,
} 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
): Promise<void> {
  try {
    // Mark job as PROCESSING
    const award = await prisma.specialAward.findUniqueOrThrow({
      where: { id: awardId },
      include: { program: true },
    })

    // Get projects
    const statusFilter = includeSubmitted
      ? (['SUBMITTED', 'ELIGIBLE', 'ASSIGNED', 'SEMIFINALIST', 'FINALIST'] as const)
      : (['ELIGIBLE', 'ASSIGNED', 'SEMIFINALIST', 'FINALIST'] as const)

    const projects = await prisma.project.findMany({
      where: {
        programId: award.programId,
        status: { in: [...statusFilter] },
      },
      select: {
        id: true,
        title: true,
        description: true,
        competitionCategory: true,
        country: true,
        geographicZone: true,
        tags: true,
        oceanIssue: true,
      },
    })

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

    // Phase 1: Auto-tag rules (deterministic, fast)
    const autoTagRules = award.autoTagRulesJson as unknown as AutoTagRule[] | null
    let autoResults: Map<string, boolean> | undefined
    if (autoTagRules && Array.isArray(autoTagRules) && autoTagRules.length > 0) {
      autoResults = applyAutoTagRules(autoTagRules, projects)
    }

    // Phase 2: 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; 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,
            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: auto-tag AND AI must agree (or just one if only one configured)
    const eligibilities = projects.map((project) => {
      const autoEligible = autoResults?.get(project.id) ?? true
      const aiEval = aiResults?.get(project.id)
      const aiEligible = aiEval?.eligible ?? true

      const eligible = autoEligible && aiEligible
      const method = autoResults && aiResults ? 'AUTO' : autoResults ? 'AUTO' : 'MANUAL'

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

    // Upsert eligibilities
    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',
            aiReasoningJson: e.aiReasoningJson ?? undefined,
          },
          update: {
            eligible: e.eligible,
            method: e.method as 'AUTO' | 'MANUAL',
            aiReasoningJson: e.aiReasoningJson ?? undefined,
            overriddenBy: null,
            overriddenAt: null,
          },
        })
      )
    )

    // 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 {
      // If we can't even update the status, log and give up
      console.error('Failed to update eligibility job status:', error)
    }
  }
}
