import { PrismaClient } from '@prisma/client'

const prisma = new PrismaClient()

interface CheckResult {
  name: string
  passed: boolean
  details: string
}

async function runChecks(): Promise<CheckResult[]> {
  const results: CheckResult[] = []

  // 1. No orphan ProjectStageState (every PSS references valid project, track, stage)
  const orphanStates = await prisma.$queryRaw<{ count: bigint }[]>`
    SELECT COUNT(*) as count FROM "ProjectStageState" pss
    WHERE NOT EXISTS (SELECT 1 FROM "Project" p WHERE p.id = pss."projectId")
       OR NOT EXISTS (SELECT 1 FROM "Track" t WHERE t.id = pss."trackId")
       OR NOT EXISTS (SELECT 1 FROM "Stage" s WHERE s.id = pss."stageId")
  `
  const orphanCount = Number(orphanStates[0]?.count ?? 0)
  results.push({
    name: 'No orphan ProjectStageState',
    passed: orphanCount === 0,
    details: orphanCount === 0 ? 'All PSS records reference valid entities' : `Found ${orphanCount} orphan records`,
  })

  // 2. Every project has at least one stage state
  const projectsWithoutState = await prisma.$queryRaw<{ count: bigint }[]>`
    SELECT COUNT(*) as count FROM "Project" p
    WHERE NOT EXISTS (SELECT 1 FROM "ProjectStageState" pss WHERE pss."projectId" = p.id)
  `
  const noStateCount = Number(projectsWithoutState[0]?.count ?? 0)
  const totalProjects = await prisma.project.count()
  results.push({
    name: 'Every project has at least one stage state',
    passed: noStateCount === 0,
    details: noStateCount === 0
      ? `All ${totalProjects} projects have stage states`
      : `${noStateCount} projects missing stage states`,
  })

  // 3. No duplicate active states per (project, track, stage)
  const duplicateStates = await prisma.$queryRaw<{ count: bigint }[]>`
    SELECT COUNT(*) as count FROM (
      SELECT "projectId", "trackId", "stageId", COUNT(*) as cnt
      FROM "ProjectStageState"
      WHERE "exitedAt" IS NULL
      GROUP BY "projectId", "trackId", "stageId"
      HAVING COUNT(*) > 1
    ) dupes
  `
  const dupeCount = Number(duplicateStates[0]?.count ?? 0)
  results.push({
    name: 'No duplicate active states per (project, track, stage)',
    passed: dupeCount === 0,
    details: dupeCount === 0 ? 'No duplicates found' : `Found ${dupeCount} duplicate active states`,
  })

  // 4. All transitions stay within same pipeline
  const crossPipelineTransitions = await prisma.$queryRaw<{ count: bigint }[]>`
    SELECT COUNT(*) as count FROM "StageTransition" st
    JOIN "Stage" sf ON sf.id = st."fromStageId"
    JOIN "Track" tf ON tf.id = sf."trackId"
    JOIN "Stage" sto ON sto.id = st."toStageId"
    JOIN "Track" tt ON tt.id = sto."trackId"
    WHERE tf."pipelineId" != tt."pipelineId"
  `
  const crossCount = Number(crossPipelineTransitions[0]?.count ?? 0)
  results.push({
    name: 'All transitions stay within same pipeline',
    passed: crossCount === 0,
    details: crossCount === 0 ? 'All transitions are within pipeline' : `Found ${crossCount} cross-pipeline transitions`,
  })

  // 5. Stage sortOrder unique per track
  const duplicateSortOrders = await prisma.$queryRaw<{ count: bigint }[]>`
    SELECT COUNT(*) as count FROM (
      SELECT "trackId", "sortOrder", COUNT(*) as cnt
      FROM "Stage"
      GROUP BY "trackId", "sortOrder"
      HAVING COUNT(*) > 1
    ) dupes
  `
  const dupeSortCount = Number(duplicateSortOrders[0]?.count ?? 0)
  results.push({
    name: 'Stage sortOrder unique per track',
    passed: dupeSortCount === 0,
    details: dupeSortCount === 0 ? 'All sort orders unique' : `Found ${dupeSortCount} duplicate sort orders`,
  })

  // 6. Track sortOrder unique per pipeline
  const duplicateTrackOrders = await prisma.$queryRaw<{ count: bigint }[]>`
    SELECT COUNT(*) as count FROM (
      SELECT "pipelineId", "sortOrder", COUNT(*) as cnt
      FROM "Track"
      GROUP BY "pipelineId", "sortOrder"
      HAVING COUNT(*) > 1
    ) dupes
  `
  const dupeTrackCount = Number(duplicateTrackOrders[0]?.count ?? 0)
  results.push({
    name: 'Track sortOrder unique per pipeline',
    passed: dupeTrackCount === 0,
    details: dupeTrackCount === 0 ? 'All track orders unique' : `Found ${dupeTrackCount} duplicate track orders`,
  })

  // 7. Every Pipeline has at least one Track; every Track has at least one Stage
  const emptyPipelines = await prisma.$queryRaw<{ count: bigint }[]>`
    SELECT COUNT(*) as count FROM "Pipeline" p
    WHERE NOT EXISTS (SELECT 1 FROM "Track" t WHERE t."pipelineId" = p.id)
  `
  const emptyPipelineCount = Number(emptyPipelines[0]?.count ?? 0)
  const emptyTracks = await prisma.$queryRaw<{ count: bigint }[]>`
    SELECT COUNT(*) as count FROM "Track" t
    WHERE NOT EXISTS (SELECT 1 FROM "Stage" s WHERE s."trackId" = t.id)
  `
  const emptyTrackCount = Number(emptyTracks[0]?.count ?? 0)
  results.push({
    name: 'Every Pipeline has Tracks; every Track has Stages',
    passed: emptyPipelineCount === 0 && emptyTrackCount === 0,
    details: emptyPipelineCount === 0 && emptyTrackCount === 0
      ? 'All pipelines have tracks and all tracks have stages'
      : `${emptyPipelineCount} empty pipelines, ${emptyTrackCount} empty tracks`,
  })

  // 8. LiveProgressCursor references valid stage
  const badCursors = await prisma.$queryRaw<{ count: bigint }[]>`
    SELECT COUNT(*) as count FROM "LiveProgressCursor" lpc
    WHERE NOT EXISTS (SELECT 1 FROM "Stage" s WHERE s.id = lpc."stageId")
  `
  const badCursorCount = Number(badCursors[0]?.count ?? 0)
  results.push({
    name: 'LiveProgressCursor references valid stage',
    passed: badCursorCount === 0,
    details: badCursorCount === 0
      ? 'All cursors reference valid stages'
      : `Found ${badCursorCount} cursors with invalid stage references`,
  })

  // 10. Cohort references valid stage
  const badCohorts = await prisma.$queryRaw<{ count: bigint }[]>`
    SELECT COUNT(*) as count FROM "Cohort" c
    WHERE NOT EXISTS (SELECT 1 FROM "Stage" s WHERE s.id = c."stageId")
  `
  const badCohortCount = Number(badCohorts[0]?.count ?? 0)
  results.push({
    name: 'Cohort references valid stage',
    passed: badCohortCount === 0,
    details: badCohortCount === 0
      ? 'All cohorts reference valid stages'
      : `Found ${badCohortCount} cohorts with invalid stage references`,
  })

  // 11. Every EvaluationForm has a valid stageId
  const badEvalForms = await prisma.$queryRaw<{ count: bigint }[]>`
    SELECT COUNT(*) as count FROM "EvaluationForm" ef
    WHERE NOT EXISTS (SELECT 1 FROM "Stage" s WHERE s.id = ef."stageId")
  `
  const badFormCount = Number(badEvalForms[0]?.count ?? 0)
  results.push({
    name: 'Every EvaluationForm references valid stage',
    passed: badFormCount === 0,
    details: badFormCount === 0
      ? 'All evaluation forms reference valid stages'
      : `Found ${badFormCount} forms with invalid stage references`,
  })

  // 12. Every FileRequirement has a valid stageId
  const badFileReqs = await prisma.$queryRaw<{ count: bigint }[]>`
    SELECT COUNT(*) as count FROM "FileRequirement" fr
    WHERE NOT EXISTS (SELECT 1 FROM "Round" r WHERE r.id = fr."roundId")
  `
  const badFileReqCount = Number(badFileReqs[0]?.count ?? 0)
  results.push({
    name: 'Every FileRequirement references valid round',
    passed: badFileReqCount === 0,
    details: badFileReqCount === 0
      ? 'All file requirements reference valid rounds'
      : `Found ${badFileReqCount} file requirements with invalid round references`,
  })

  // 13. Count validation
  const projectCountResult = await prisma.project.count()
  const roundCount = await prisma.round.count()
  const competitionCount = await prisma.competition.count()
  const prsCount = await prisma.projectRoundState.count()
  results.push({
    name: 'Count validation',
    passed: projectCountResult > 0 && roundCount > 0 && competitionCount > 0,
    details: `Competitions: ${competitionCount}, Rounds: ${roundCount}, Projects: ${projectCountResult}, RoundStates: ${prsCount}`,
  })

  return results
}

async function main() {
  console.log('🔍 Running integrity checks...\n')

  const results = await runChecks()

  let allPassed = true
  for (const result of results) {
    const icon = result.passed ? '✅' : '❌'
    console.log(`${icon} ${result.name}`)
    console.log(`   ${result.details}\n`)
    if (!result.passed) allPassed = false
  }

  console.log('='.repeat(50))
  if (allPassed) {
    console.log('✅ All integrity checks passed!')
  } else {
    console.log('❌ Some integrity checks failed!')
    process.exit(1)
  }
}

main()
  .catch((e) => {
    console.error('❌ Integrity check failed:', e)
    process.exit(1)
  })
  .finally(async () => {
    await prisma.$disconnect()
  })
