'use client'

import { use, useState, useEffect, useRef, useCallback } from 'react'
import { useRouter } from 'next/navigation'
import Link from 'next/link'
import type { Route } from 'next'
import { trpc } from '@/lib/trpc/client'
import { Card, CardContent } from '@/components/ui/card'
import { Button } from '@/components/ui/button'
import { Skeleton } from '@/components/ui/skeleton'
import { MultiWindowDocViewer } from '@/components/jury/multi-window-doc-viewer'
import { Badge } from '@/components/ui/badge'
import { COIDeclarationDialog } from '@/components/forms/coi-declaration-dialog'
import { ArrowLeft, Save, Send, AlertCircle, Clock, ShieldAlert, Lock } from 'lucide-react'
import { toast } from 'sonner'
import type { EvaluationConfig } from '@/types/competition-configs'
import {
  EvaluationFormFields,
  parseCriteriaFromForm,
} from '@/components/evaluation/evaluation-form-fields'

type PageProps = {
  params: Promise<{ roundId: string; projectId: string }>
}

export default function JuryEvaluatePage({ params: paramsPromise }: PageProps) {
  const params = use(paramsPromise)
  const router = useRouter()
  const { roundId, projectId } = params
  const utils = trpc.useUtils()

  // Evaluation form state — stores all criterion values (numeric, boolean, text)
  const [criteriaValues, setCriteriaValues] = useState<Record<string, number | boolean | string>>({})
  const [globalScore, setGlobalScore] = useState('')
  const [binaryDecision, setBinaryDecision] = useState<'accept' | 'reject' | ''>('')
  const [feedbackText, setFeedbackText] = useState('')

  // Track dirty state for autosave
  const isDirtyRef = useRef(false)
  const evaluationIdRef = useRef<string | null>(null)
  const isSubmittedRef = useRef(false)
  const isSubmittingRef = useRef(false)
  const [isSubmitting, setIsSubmitting] = useState(false)
  const startPromiseRef = useRef<Promise<{ id: string }> | null>(null)
  const autosaveTimerRef = useRef<ReturnType<typeof setTimeout> | null>(null)
  const [lastSavedAt, setLastSavedAt] = useState<Date | null>(null)

  // Fetch project
  const { data: project } = trpc.project.get.useQuery(
    { id: projectId },
    { enabled: !!projectId }
  )

  // Fetch round to get config
  const { data: round } = trpc.round.getById.useQuery(
    { id: roundId },
    { enabled: !!roundId }
  )

  // Fetch assignment to get evaluation
  const { data: assignment } = trpc.roundAssignment.getMyAssignments.useQuery(
    { roundId },
    { enabled: !!roundId }
  )

  const myAssignment = assignment?.find((a) => a.projectId === projectId)

  // Fetch existing evaluation if it exists
  const { data: existingEvaluation } = trpc.evaluation.get.useQuery(
    { assignmentId: myAssignment?.id ?? '' },
    { enabled: !!myAssignment?.id }
  )

  // COI (Conflict of Interest) check
  const { data: coiStatus, isLoading: coiLoading } = trpc.evaluation.getCOIStatus.useQuery(
    { assignmentId: myAssignment?.id ?? '' },
    { enabled: !!myAssignment?.id }
  )
  const [coiCompleted, setCOICompleted] = useState(false)
  const [coiHasConflict, setCOIHasConflict] = useState(false)

  // Fetch the active evaluation form for this round (category-aware)
  const { data: activeForm } = trpc.evaluation.getStageForm.useQuery(
    { roundId, category: project?.competitionCategory },
    { enabled: !!roundId && !!project }
  )

  // Start evaluation mutation (creates draft)
  const startMutation = trpc.evaluation.start.useMutation()

  // Autosave mutation (silent)
  const autosaveMutation = trpc.evaluation.autosave.useMutation({
    onSuccess: () => {
      isDirtyRef.current = false
      setLastSavedAt(new Date())
    },
  })

  // Submit mutation
  const submitMutation = trpc.evaluation.submit.useMutation({
    onSuccess: () => {
      isSubmittedRef.current = true
      isDirtyRef.current = false
      utils.roundAssignment.getMyAssignments.invalidate()
      utils.evaluation.get.invalidate()
      toast.success('Evaluation submitted successfully')
      router.push(`/jury/competitions/${roundId}` as Route)
    },
    onError: (err) => toast.error(err.message),
  })

  // Track evaluation ID
  useEffect(() => {
    if (existingEvaluation?.id) {
      evaluationIdRef.current = existingEvaluation.id
    }
  }, [existingEvaluation?.id])

  // Load existing evaluation data
  useEffect(() => {
    if (existingEvaluation) {
      if (existingEvaluation.criterionScoresJson) {
        const values: Record<string, number | boolean | string> = {}
        Object.entries(existingEvaluation.criterionScoresJson).forEach(([key, value]) => {
          if (typeof value === 'number' || typeof value === 'boolean' || typeof value === 'string') {
            values[key] = value
          }
        })
        setCriteriaValues(values)
      }
      if (existingEvaluation.globalScore) {
        setGlobalScore(existingEvaluation.globalScore.toString())
      }
      if (existingEvaluation.binaryDecision !== null) {
        setBinaryDecision(existingEvaluation.binaryDecision ? 'accept' : 'reject')
      }
      if (existingEvaluation.feedbackText) {
        setFeedbackText(existingEvaluation.feedbackText)
      }
      isDirtyRef.current = false
    }
  }, [existingEvaluation])

  // Parse evaluation config from round
  const evalConfig: EvaluationConfig | null = round?.configJson as EvaluationConfig | null
  const scoringMode = evalConfig?.scoringMode ?? 'criteria'
  const requireFeedback = evalConfig?.requireFeedback ?? true
  const feedbackMinLength = evalConfig?.feedbackMinLength ?? 10

  // Parse criteria from the active form (shared with admin proxy flow)
  const criteria = parseCriteriaFromForm(
    activeForm?.criteriaJson as ReadonlyArray<Record<string, unknown>> | null | undefined,
  )

  // Initialize numeric criteria with midpoint values so slider visual matches stored value.
  const criteriaInitializedRef = useRef(false)
  useEffect(() => {
    if (criteriaInitializedRef.current || criteria.length === 0) return
    if (existingEvaluation?.criterionScoresJson) return
    criteriaInitializedRef.current = true

    const defaults: Record<string, number | boolean | string> = {}
    for (const c of criteria) {
      if (c.type === 'numeric') {
        defaults[c.id] = Math.ceil((c.minScore + c.maxScore) / 2)
      }
    }
    if (Object.keys(defaults).length > 0) {
      setCriteriaValues((prev) => ({ ...defaults, ...prev }))
    }
  }, [criteria, existingEvaluation?.criterionScoresJson])

  // Build current form data for autosave
  const buildSavePayload = useCallback(() => {
    return {
      criterionScoresJson: scoringMode === 'criteria' ? criteriaValues : undefined,
      globalScore: scoringMode === 'global' && globalScore ? parseInt(globalScore, 10) : null,
      binaryDecision: scoringMode === 'binary' && binaryDecision ? binaryDecision === 'accept' : null,
      feedbackText: feedbackText || null,
    }
  }, [scoringMode, criteriaValues, globalScore, binaryDecision, feedbackText])

  // Perform autosave
  const performAutosave = useCallback(async () => {
    if (!isDirtyRef.current || isSubmittedRef.current || isSubmittingRef.current) return
    if (existingEvaluation?.status === 'SUBMITTED') return

    let evalId = evaluationIdRef.current
    if (!evalId && myAssignment) {
      try {
        // Reuse in-flight start promise to avoid duplicate creation
        if (!startPromiseRef.current) {
          startPromiseRef.current = startMutation.mutateAsync({ assignmentId: myAssignment.id })
        }
        const newEval = await startPromiseRef.current
        evalId = newEval.id
        evaluationIdRef.current = evalId
      } catch {
        return
      } finally {
        startPromiseRef.current = null
      }
    }
    if (!evalId) return

    autosaveMutation.mutate({ id: evalId, ...buildSavePayload() })
  }, [myAssignment, existingEvaluation?.status, startMutation, autosaveMutation, buildSavePayload])

  // Debounced autosave: save 3 seconds after last change
  useEffect(() => {
    if (!isDirtyRef.current) return

    if (autosaveTimerRef.current) {
      clearTimeout(autosaveTimerRef.current)
    }

    autosaveTimerRef.current = setTimeout(() => {
      performAutosave()
    }, 3000)

    return () => {
      if (autosaveTimerRef.current) {
        clearTimeout(autosaveTimerRef.current)
      }
    }
  }, [criteriaValues, globalScore, binaryDecision, feedbackText, performAutosave])

  // Save on page leave (beforeunload)
  useEffect(() => {
    const handleBeforeUnload = () => {
      if (isDirtyRef.current && !isSubmittedRef.current && evaluationIdRef.current) {
        const payload = JSON.stringify({
          id: evaluationIdRef.current,
          ...buildSavePayload(),
        })
        navigator.sendBeacon?.('/api/trpc/evaluation.autosave', payload)
      }
    }

    window.addEventListener('beforeunload', handleBeforeUnload)
    return () => window.removeEventListener('beforeunload', handleBeforeUnload)
  }, [buildSavePayload])

  // Save on component unmount (navigating away within the app)
  useEffect(() => {
    return () => {
      if (isDirtyRef.current && !isSubmittedRef.current && evaluationIdRef.current) {
        performAutosave()
      }
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [])

  // Mark dirty when form values change
  const handleCriterionChange = (key: string, value: number | boolean | string) => {
    setCriteriaValues((prev) => ({ ...prev, [key]: value }))
    isDirtyRef.current = true
  }

  const handleGlobalScoreChange = (value: string) => {
    setGlobalScore(value)
    isDirtyRef.current = true
  }

  const handleBinaryChange = (value: 'accept' | 'reject') => {
    setBinaryDecision(value)
    isDirtyRef.current = true
  }

  const handleFeedbackChange = (value: string) => {
    setFeedbackText(value)
    isDirtyRef.current = true
  }

  const handleSaveDraft = async () => {
    if (!myAssignment) {
      toast.error('Assignment not found')
      return
    }

    let evaluationId = evaluationIdRef.current
    if (!evaluationId) {
      if (!startPromiseRef.current) {
        startPromiseRef.current = startMutation.mutateAsync({ assignmentId: myAssignment.id })
      }
      const newEval = await startPromiseRef.current
      startPromiseRef.current = null
      evaluationId = newEval.id
      evaluationIdRef.current = evaluationId
    }

    autosaveMutation.mutate(
      { id: evaluationId, ...buildSavePayload() },
      { onSuccess: () => {
        isDirtyRef.current = false
        setLastSavedAt(new Date())
        toast.success('Draft saved', { duration: 1500 })
      }}
    )
  }

  const handleSubmit = async () => {
    // Cancel any pending autosave to avoid race conditions
    if (autosaveTimerRef.current) {
      clearTimeout(autosaveTimerRef.current)
      autosaveTimerRef.current = null
    }
    isSubmittingRef.current = true
    setIsSubmitting(true)

    if (!myAssignment) {
      toast.error('Assignment not found')
      isSubmittingRef.current = false
      setIsSubmitting(false)
      return
    }

    // Validation for criteria mode
    if (scoringMode === 'criteria') {
      const requiredCriteria = criteria.filter((c) =>
        c.type !== 'section_header' && c.required
      )
      for (const c of requiredCriteria) {
        const val = criteriaValues[c.id]
        if (c.type === 'numeric' && (val === undefined || val === null)) {
          toast.error(`Please score "${c.label}"`)
          isSubmittingRef.current = false
          setIsSubmitting(false)
          return
        }
        if ((c.type === 'boolean' || c.type === 'advance') && val === undefined) {
          toast.error(`Please answer "${c.label}"`)
          isSubmittingRef.current = false
          setIsSubmitting(false)
          return
        }
        if (c.type === 'text' && (!val || (typeof val === 'string' && !val.trim()))) {
          toast.error(`Please fill in "${c.label}"`)
          isSubmittingRef.current = false
          setIsSubmitting(false)
          return
        }
      }
    }

    if (scoringMode === 'global') {
      const score = parseInt(globalScore, 10)
      if (isNaN(score) || score < 1 || score > 10) {
        toast.error('Please enter a valid score between 1 and 10')
        isSubmittingRef.current = false
        setIsSubmitting(false)
        return
      }
    }

    if (scoringMode === 'binary') {
      if (!binaryDecision) {
        toast.error('Please select accept or reject')
        isSubmittingRef.current = false
        setIsSubmitting(false)
        return
      }
    }

    if (requireFeedback) {
      if (!feedbackText.trim() || feedbackText.length < feedbackMinLength) {
        toast.error(`Please provide feedback (minimum ${feedbackMinLength} characters)`)
        isSubmittingRef.current = false
        setIsSubmitting(false)
        return
      }
    }

    // Reuse in-flight start promise to avoid duplicate creation (e.g. if autosave is mid-flight)
    let evaluationId = evaluationIdRef.current
    if (!evaluationId) {
      if (!startPromiseRef.current) {
        startPromiseRef.current = startMutation.mutateAsync({ assignmentId: myAssignment.id })
      }
      const newEval = await startPromiseRef.current
      startPromiseRef.current = null
      evaluationId = newEval.id
      evaluationIdRef.current = evaluationId
    }

    // Compute a weighted global score from numeric criteria for the global score field
    const numericCriteria = criteria.filter((c) => c.type === 'numeric')
    let computedGlobalScore = 5
    if (scoringMode === 'criteria' && numericCriteria.length > 0) {
      let totalWeight = 0
      let weightedSum = 0
      for (const c of numericCriteria) {
        const val = criteriaValues[c.id]
        if (typeof val === 'number') {
          const w = c.weight ?? 1
          // Normalize to 1-10 scale
          const normalized = ((val - c.minScore) / (c.maxScore - c.minScore)) * 9 + 1
          weightedSum += normalized * w
          totalWeight += w
        }
      }
      if (totalWeight > 0) {
        computedGlobalScore = Math.round(weightedSum / totalWeight)
      }
    }

    try {
      await submitMutation.mutateAsync({
        id: evaluationId,
        criterionScoresJson: scoringMode === 'criteria' ? criteriaValues : {},
        globalScore: scoringMode === 'global' ? parseInt(globalScore, 10) : computedGlobalScore,
        binaryDecision: scoringMode === 'binary' ? binaryDecision === 'accept' : true,
        feedbackText: feedbackText || 'No feedback provided',
      })
    } catch {
      // Error toast already handled by onError callback
      isSubmittingRef.current = false
      setIsSubmitting(false)
    }
  }

  if (!round || !project) {
    return (
      <div className="space-y-6">
        <Skeleton className="h-10 w-64" />
        <Card>
          <CardContent className="py-12">
            <div className="flex items-center justify-center">
              <Skeleton className="h-64 w-full" />
            </div>
          </CardContent>
        </Card>
      </div>
    )
  }

  // COI config
  const coiRequired = evalConfig?.coiRequired ?? true

  // Determine COI state: declared via server or just completed in this session
  // coiStatus is null when no COI record exists, truthy when declared
  const coiDeclared = coiCompleted || (coiStatus != null)
  const coiConflict = coiHasConflict || (coiStatus?.hasConflict ?? false)

  // Check if round is active
  const isRoundActive = round.status === 'ROUND_ACTIVE'
  const isSubmittedEvaluation = existingEvaluation?.status === 'SUBMITTED'

  // If round is not active and no submitted evaluation to view, block access
  if (!isRoundActive && !isSubmittedEvaluation) {
    return (
      <div className="space-y-6">
        <div className="flex items-center gap-4">
          <Button variant="ghost" size="sm" asChild>
            <Link href={`/jury/competitions/${roundId}/projects/${projectId}` as Route}>
              <ArrowLeft className="mr-2 h-4 w-4" />
              Back to Project
            </Link>
          </Button>
        </div>
        <Card className="border-l-4 border-l-amber-500">
          <CardContent className="flex items-start gap-4 p-6">
            <div className="rounded-xl bg-amber-50 p-3">
              <Clock className="h-6 w-6 text-amber-600" />
            </div>
            <div>
              <h2 className="text-lg font-semibold">Evaluation Not Available</h2>
              <p className="text-sm text-muted-foreground mt-1">
                This round is not currently active. Evaluations can only be submitted during an active round.
              </p>
              <Button variant="outline" size="sm" className="mt-4" asChild>
                <Link href={`/jury/competitions/${roundId}/projects/${projectId}` as Route}>
                  View Project Details
                </Link>
              </Button>
            </div>
          </CardContent>
        </Card>
      </div>
    )
  }

  // Read-only view for submitted evaluations in closed rounds
  const isReadOnly = !isRoundActive && isSubmittedEvaluation

  // COI gate: if COI is required, not yet declared, and we have an assignment (skip for read-only views)
  if (coiRequired && !isReadOnly && myAssignment && !coiLoading && !coiDeclared) {
    return (
      <div className="space-y-6">
        <div className="flex items-center gap-4">
          <Button variant="ghost" size="sm" asChild>
            <Link href={`/jury/competitions/${roundId}/projects/${projectId}` as Route}>
              <ArrowLeft className="mr-2 h-4 w-4" />
              Back to Project
            </Link>
          </Button>
          <div>
            <h1 className="text-2xl font-bold tracking-tight text-brand-blue">
              Evaluate Project
            </h1>
            <p className="text-muted-foreground mt-1">{project.title}</p>
          </div>
        </div>
        <COIDeclarationDialog
          open={true}
          assignmentId={myAssignment.id}
          projectTitle={project.title}
          onComplete={(hasConflict) => {
            setCOICompleted(true)
            setCOIHasConflict(hasConflict)
          }}
        />
      </div>
    )
  }

  // COI conflict declared — block evaluation (skip for read-only views)
  if (coiRequired && !isReadOnly && coiConflict) {
    return (
      <div className="space-y-6">
        <div className="flex items-center gap-4">
          <Button variant="ghost" size="sm" asChild>
            <Link href={`/jury/competitions/${roundId}/projects/${projectId}` as Route}>
              <ArrowLeft className="mr-2 h-4 w-4" />
              Back to Project
            </Link>
          </Button>
          <div>
            <h1 className="text-2xl font-bold tracking-tight text-brand-blue">
              Evaluate Project
            </h1>
            <p className="text-muted-foreground mt-1">{project.title}</p>
          </div>
        </div>
        <Card className="border-l-4 border-l-amber-500">
          <CardContent className="flex items-start gap-4 p-6">
            <div className="rounded-xl bg-amber-50 p-3">
              <ShieldAlert className="h-6 w-6 text-amber-600" />
            </div>
            <div>
              <h2 className="text-lg font-semibold">Conflict of Interest Declared</h2>
              <p className="text-sm text-muted-foreground mt-1">
                You declared a conflict of interest for this project. An administrator will
                review your declaration. You cannot evaluate this project while the conflict
                is under review.
              </p>
              <Button variant="outline" size="sm" className="mt-4" asChild>
                <Link href={`/jury/competitions/${roundId}` as Route}>
                  Back to Round
                </Link>
              </Button>
            </div>
          </CardContent>
        </Card>
      </div>
    )
  }

  return (
    <div className="space-y-6">
      <div className="flex items-center gap-4">
        {isReadOnly ? (
          <Button variant="ghost" size="sm" onClick={() => router.back()}>
            <ArrowLeft className="mr-2 h-4 w-4" />
            Back
          </Button>
        ) : (
          <Button variant="ghost" size="sm" asChild>
            <Link href={`/jury/competitions/${roundId}/projects/${projectId}` as Route}>
              <ArrowLeft className="mr-2 h-4 w-4" />
              Back to Project
            </Link>
          </Button>
        )}
        <div>
          <h1 className="text-2xl font-bold tracking-tight text-brand-blue">
            {isReadOnly ? 'Submitted Evaluation' : 'Evaluate Project'}
          </h1>
          <div className="flex items-center gap-2 mt-1">
            <p className="text-muted-foreground">{project.title}</p>
            {project.competitionCategory && (
              <Badge
                variant="secondary"
                className={
                  project.competitionCategory === 'STARTUP'
                    ? 'bg-violet-100 text-violet-700 border-violet-200'
                    : 'bg-sky-100 text-sky-700 border-sky-200'
                }
              >
                {project.competitionCategory === 'STARTUP' ? 'Startup' : 'Business Concept'}
              </Badge>
            )}
          </div>
        </div>
      </div>

      {isReadOnly && (
        <Card className="border-l-4 border-l-blue-500 bg-blue-50/50">
          <CardContent className="flex items-start gap-3 p-4">
            <Lock className="h-5 w-5 text-blue-600 shrink-0 mt-0.5" />
            <div className="flex-1">
              <p className="font-medium text-sm">View-Only</p>
              <p className="text-sm text-muted-foreground mt-1">
                This evaluation has been submitted and the round is now closed. You are viewing a read-only copy of your submission.
              </p>
            </div>
          </CardContent>
        </Card>
      )}

      {/* Project Documents */}
      <MultiWindowDocViewer roundId={roundId} projectId={projectId} />

      {!isReadOnly && (
        <Card className="border-l-4 border-l-amber-500">
          <CardContent className="flex items-start gap-3 p-4">
            <AlertCircle className="h-5 w-5 text-amber-600 shrink-0 mt-0.5" />
            <div className="flex-1">
              <p className="font-medium text-sm">Important Reminder</p>
              <p className="text-sm text-muted-foreground mt-1">
                Your evaluation will be used to assess this project. Please provide thoughtful and
                constructive feedback. Your progress is automatically saved as a draft.
              </p>
            </div>
          </CardContent>
        </Card>
      )}

      <EvaluationFormFields
        criteria={criteria}
        scoringMode={scoringMode}
        requireFeedback={requireFeedback}
        feedbackMinLength={feedbackMinLength}
        criteriaValues={criteriaValues}
        globalScore={globalScore}
        binaryDecision={binaryDecision}
        feedbackText={feedbackText}
        isReadOnly={isReadOnly}
        lastSavedAt={lastSavedAt}
        onCriterionChange={handleCriterionChange}
        onGlobalScoreChange={handleGlobalScoreChange}
        onBinaryChange={handleBinaryChange}
        onFeedbackChange={handleFeedbackChange}
      />


      {isReadOnly ? (
        <div className="flex items-center">
          <Button
            variant="outline"
            onClick={() => router.back()}
          >
            <ArrowLeft className="mr-2 h-4 w-4" />
            Back
          </Button>
        </div>
      ) : (
        <div className="flex items-center justify-between flex-wrap gap-4">
          <Button
            variant="outline"
            onClick={() => router.push(`/jury/competitions/${roundId}/projects/${projectId}` as Route)}
          >
            Cancel
          </Button>
          <div className="flex gap-3">
            <Button
              variant="outline"
              onClick={handleSaveDraft}
              disabled={autosaveMutation.isPending || submitMutation.isPending}
            >
              <Save className="mr-2 h-4 w-4" />
              {autosaveMutation.isPending ? 'Saving...' : 'Save Draft'}
            </Button>
            <Button
              onClick={handleSubmit}
              disabled={submitMutation.isPending || isSubmitting}
              className="bg-brand-blue hover:bg-brand-blue-light"
            >
              <Send className="mr-2 h-4 w-4" />
              {submitMutation.isPending ? 'Submitting...' : 'Submit Evaluation'}
            </Button>
          </div>
        </div>
      )}
    </div>
  )
}
