'use client'

import { useState, useMemo, useCallback, useEffect } from 'react'
import { useRouter } from 'next/navigation'
import { useForm, UseFormReturn } from 'react-hook-form'
import { zodResolver } from '@hookform/resolvers/zod'
import { z } from 'zod'
import { motion, AnimatePresence } from 'motion/react'
import {
  Waves,
  AlertCircle,
  Loader2,
  CheckCircle,
  ArrowLeft,
  ArrowRight,
  Clock,
} from 'lucide-react'
import { Button } from '@/components/ui/button'
import { Input } from '@/components/ui/input'
import { Textarea } from '@/components/ui/textarea'
import { Label } from '@/components/ui/label'
import { Checkbox } from '@/components/ui/checkbox'
import {
  Select,
  SelectContent,
  SelectItem,
  SelectTrigger,
  SelectValue,
} from '@/components/ui/select'
import { cn } from '@/lib/utils'
import {
  StepWelcome,
  StepContact,
  StepProject,
  StepTeam,
  StepAdditional,
  StepReview,
} from './apply-steps'
import type { WizardConfig, WizardStepId, CustomField } from '@/types/wizard-config'
import {
  getVisibleSteps,
  isFieldVisible,
  isFieldRequired,
  buildStepsArray,
  getCustomFieldsForStep,
} from '@/lib/wizard-config'
import { TeamMemberRole } from '@prisma/client'

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

interface ApplyWizardDynamicProps {
  mode: 'edition' | 'round'
  config: WizardConfig
  programName: string
  programYear: number
  programId?: string
  roundId?: string
  isOpen: boolean
  submissionDeadline?: Date | string | null
  onSubmit: (data: Record<string, unknown>) => Promise<void>
  isSubmitting: boolean
}

// ---------------------------------------------------------------------------
// Animation variants
// ---------------------------------------------------------------------------

const variants = {
  enter: (dir: number) => ({ x: dir > 0 ? 50 : -50, opacity: 0 }),
  center: { x: 0, opacity: 1 },
  exit: (dir: number) => ({ x: dir < 0 ? 50 : -50, opacity: 0 }),
}

// ---------------------------------------------------------------------------
// Custom field renderer
// ---------------------------------------------------------------------------

function CustomFieldRenderer({
  field,
  form,
}: {
  field: CustomField
  form: UseFormReturn<Record<string, unknown>>
}) {
  const {
    register,
    formState: { errors },
    setValue,
    watch,
  } = form

  const value = watch(field.id)
  const error = errors[field.id]

  const labelEl = (
    <Label htmlFor={field.id}>
      {field.label}
      {field.required ? (
        <span className="text-destructive"> *</span>
      ) : (
        <span className="text-muted-foreground text-xs ml-1">(optional)</span>
      )}
    </Label>
  )

  const helpEl = field.helpText ? (
    <p className="text-xs text-muted-foreground">{field.helpText}</p>
  ) : null

  const errorEl = error ? (
    <p className="text-sm text-destructive">{error.message as string}</p>
  ) : null

  switch (field.type) {
    case 'text':
      return (
        <div className="space-y-2">
          {labelEl}
          {helpEl}
          <Input
            id={field.id}
            placeholder={field.placeholder}
            {...register(field.id)}
            className="h-12 text-base"
          />
          {errorEl}
        </div>
      )

    case 'textarea':
      return (
        <div className="space-y-2">
          {labelEl}
          {helpEl}
          <Textarea
            id={field.id}
            placeholder={field.placeholder}
            rows={4}
            {...register(field.id)}
            className="text-base resize-none"
          />
          {errorEl}
        </div>
      )

    case 'number':
      return (
        <div className="space-y-2">
          {labelEl}
          {helpEl}
          <Input
            id={field.id}
            type="number"
            placeholder={field.placeholder}
            {...register(field.id)}
            className="h-12 text-base"
          />
          {errorEl}
        </div>
      )

    case 'select':
      return (
        <div className="space-y-2">
          {labelEl}
          {helpEl}
          <Select
            value={(value as string) ?? ''}
            onValueChange={(v) => setValue(field.id, v)}
          >
            <SelectTrigger className="h-12 text-base">
              <SelectValue placeholder={field.placeholder ?? 'Select...'} />
            </SelectTrigger>
            <SelectContent>
              {(field.options ?? []).map((opt) => (
                <SelectItem key={opt} value={opt}>
                  {opt}
                </SelectItem>
              ))}
            </SelectContent>
          </Select>
          {errorEl}
        </div>
      )

    case 'multiselect': {
      const selected: string[] = Array.isArray(value) ? (value as string[]) : []
      return (
        <div className="space-y-2">
          {labelEl}
          {helpEl}
          <div className="space-y-2 rounded-lg border p-3">
            {(field.options ?? []).map((opt) => {
              const checked = selected.includes(opt)
              return (
                <div key={opt} className="flex items-center gap-2">
                  <Checkbox
                    id={`${field.id}-${opt}`}
                    checked={checked}
                    onCheckedChange={(c) => {
                      if (c) {
                        setValue(field.id, [...selected, opt])
                      } else {
                        setValue(
                          field.id,
                          selected.filter((s) => s !== opt)
                        )
                      }
                    }}
                  />
                  <Label htmlFor={`${field.id}-${opt}`} className="text-sm font-normal">
                    {opt}
                  </Label>
                </div>
              )
            })}
          </div>
          {errorEl}
        </div>
      )
    }

    case 'checkbox':
      return (
        <div className="space-y-2">
          <div className="flex items-center gap-2">
            <Checkbox
              id={field.id}
              checked={value === true}
              onCheckedChange={(c) => setValue(field.id, c === true)}
            />
            <Label htmlFor={field.id} className="text-sm font-normal">
              {field.label}
              {field.required && <span className="text-destructive"> *</span>}
            </Label>
          </div>
          {helpEl}
          {errorEl}
        </div>
      )

    case 'date':
      return (
        <div className="space-y-2">
          {labelEl}
          {helpEl}
          <Input
            id={field.id}
            type="date"
            {...register(field.id)}
            className="h-12 text-base"
          />
          {errorEl}
        </div>
      )

    default:
      return null
  }
}

// ---------------------------------------------------------------------------
// Dynamic schema builder
// ---------------------------------------------------------------------------

function buildDynamicSchema(config: WizardConfig): z.ZodObject<Record<string, z.ZodTypeAny>> {
  const shape: Record<string, z.ZodTypeAny> = {}

  // Always required
  shape.competitionCategory = z.string().min(1, 'Competition category is required')
  shape.gdprConsent = z.boolean().refine((val) => val === true, {
    message: 'You must agree to the data processing terms',
  })

  // Contact fields
  if (isFieldVisible(config, 'contactName')) {
    shape.contactName = isFieldRequired(config, 'contactName')
      ? z.string().min(2, 'Full name is required')
      : z.string().optional()
  } else {
    shape.contactName = z.string().optional()
  }

  if (isFieldVisible(config, 'contactEmail')) {
    shape.contactEmail = isFieldRequired(config, 'contactEmail')
      ? z.string().email('Invalid email address')
      : z.string().optional()
  } else {
    shape.contactEmail = z.string().optional()
  }

  if (isFieldVisible(config, 'contactPhone')) {
    shape.contactPhone = isFieldRequired(config, 'contactPhone')
      ? z.string().min(5, 'Phone number is required')
      : z.string().optional()
  } else {
    shape.contactPhone = z.string().optional()
  }

  if (isFieldVisible(config, 'country')) {
    shape.country = isFieldRequired(config, 'country')
      ? z.string().min(2, 'Country is required')
      : z.string().optional()
  } else {
    shape.country = z.string().optional()
  }

  shape.city = z.string().optional()

  // Project fields
  if (isFieldVisible(config, 'projectName')) {
    shape.projectName = isFieldRequired(config, 'projectName')
      ? z.string().min(2, 'Project name is required').max(200)
      : z.string().optional()
  } else {
    shape.projectName = z.string().optional()
  }

  shape.teamName = z.string().optional()

  if (isFieldVisible(config, 'description')) {
    shape.description = isFieldRequired(config, 'description')
      ? z.string().min(20, 'Description must be at least 20 characters')
      : z.string().optional()
  } else {
    shape.description = z.string().optional()
  }

  if (isFieldVisible(config, 'oceanIssue')) {
    shape.oceanIssue = isFieldRequired(config, 'oceanIssue')
      ? z.string().min(1, 'Ocean issue is required')
      : z.string().optional()
  } else {
    shape.oceanIssue = z.string().optional()
  }

  // Team members
  if (config.features?.enableTeamMembers !== false) {
    shape.teamMembers = z
      .array(
        z.object({
          name: z.string().min(1, 'Name is required'),
          email: z.string().email('Invalid email address'),
          role: z.nativeEnum(TeamMemberRole).default('MEMBER'),
          title: z.string().optional(),
        })
      )
      .optional()
  }

  // Additional fields - always optional at schema level
  shape.institution = z.string().optional()
  shape.startupCreatedDate = z.string().optional()
  shape.wantsMentorship = z.boolean().default(false)
  shape.referralSource = z.string().optional()

  // Custom fields
  for (const cf of config.customFields ?? []) {
    if (cf.required) {
      if (cf.type === 'checkbox') {
        shape[cf.id] = z.boolean().refine((v) => v === true, { message: `${cf.label} is required` })
      } else if (cf.type === 'multiselect') {
        shape[cf.id] = z.array(z.string()).min(1, `${cf.label} is required`)
      } else {
        shape[cf.id] = z.string().min(1, `${cf.label} is required`)
      }
    } else {
      if (cf.type === 'checkbox') {
        shape[cf.id] = z.boolean().optional()
      } else if (cf.type === 'multiselect') {
        shape[cf.id] = z.array(z.string()).optional()
      } else {
        shape[cf.id] = z.string().optional()
      }
    }
  }

  return z.object(shape)
}

// ---------------------------------------------------------------------------
// Main component
// ---------------------------------------------------------------------------

export function ApplyWizardDynamic({
  mode,
  config,
  programName,
  programYear,
  programId,
  roundId,
  isOpen,
  submissionDeadline,
  onSubmit,
  isSubmitting,
}: ApplyWizardDynamicProps) {
  const router = useRouter()

  const [currentStep, setCurrentStep] = useState(0)
  const [direction, setDirection] = useState(0)
  const [submitted, setSubmitted] = useState(false)
  const [submissionMessage, setSubmissionMessage] = useState('')

  // Build dynamic schema from config
  const schema = useMemo(() => buildDynamicSchema(config), [config])

  // Build default values
  const defaultValues = useMemo(() => {
    const defaults: Record<string, unknown> = {
      competitionCategory: undefined,
      contactName: '',
      contactEmail: '',
      contactPhone: '',
      country: '',
      city: '',
      projectName: '',
      teamName: '',
      description: '',
      oceanIssue: undefined,
      teamMembers: [],
      institution: '',
      startupCreatedDate: '',
      wantsMentorship: false,
      referralSource: '',
      gdprConsent: false,
    }

    // Add defaults for custom fields
    for (const cf of config.customFields ?? []) {
      if (cf.type === 'checkbox') {
        defaults[cf.id] = false
      } else if (cf.type === 'multiselect') {
        defaults[cf.id] = []
      } else {
        defaults[cf.id] = ''
      }
    }

    return defaults
  }, [config])

  const form = useForm<Record<string, unknown>>({
    resolver: zodResolver(schema),
    defaultValues,
    mode: 'onChange',
  })

  const { watch, trigger, handleSubmit } = form
  const formValues = watch()
  const competitionCategory = formValues.competitionCategory as string | undefined

  const isBusinessConcept = competitionCategory === 'BUSINESS_CONCEPT'
  const isStartup = competitionCategory === 'STARTUP'

  // Visible steps from config
  const visibleSteps = useMemo(
    () => getVisibleSteps(config, formValues as Record<string, unknown>),
    [config, formValues]
  )

  // Steps array for validation mapping
  const stepsArray = useMemo(() => buildStepsArray(config), [config])

  // Filtered steps array matching visible step IDs
  const activeSteps = useMemo(() => {
    const visibleIds = new Set(visibleSteps.map((s) => s.id as string))
    return stepsArray.filter((s) => visibleIds.has(s.id))
  }, [stepsArray, visibleSteps])

  // Validate current step fields
  const validateCurrentStep = useCallback(async () => {
    if (currentStep >= activeSteps.length) return true
    const stepDef = activeSteps[currentStep]
    const fields = stepDef.fields as string[]

    // Also validate custom fields for this step
    const customFields = getCustomFieldsForStep(config, stepDef.id as WizardStepId)
    const customFieldIds = customFields.map((cf) => cf.id)

    const allFields = [...fields, ...customFieldIds]
    if (allFields.length === 0) return true
    return await trigger(allFields)
  }, [currentStep, activeSteps, config, trigger])

  // Navigation
  const nextStep = useCallback(async () => {
    const isValid = await validateCurrentStep()
    if (isValid && currentStep < activeSteps.length - 1) {
      setDirection(1)
      setCurrentStep((prev) => prev + 1)
      window.scrollTo({ top: 0, behavior: 'smooth' })
    }
  }, [validateCurrentStep, currentStep, activeSteps.length])

  const prevStep = useCallback(() => {
    if (currentStep > 0) {
      setDirection(-1)
      setCurrentStep((prev) => prev - 1)
      window.scrollTo({ top: 0, behavior: 'smooth' })
    }
  }, [currentStep])

  // Handle form submit
  const handleFormSubmit = useCallback(
    async (data: Record<string, unknown>) => {
      try {
        await onSubmit(data)
        setSubmitted(true)
        setSubmissionMessage(
          'Thank you for your application! You will receive a confirmation email shortly.'
        )
      } catch {
        // Error handled by parent via onSubmit rejection
      }
    },
    [onSubmit]
  )

  // Keyboard navigation (skip when focused on textarea or contenteditable)
  useEffect(() => {
    const handleKeyDown = (e: KeyboardEvent) => {
      const target = e.target as HTMLElement
      const isTextarea = target.tagName === 'TEXTAREA'
      const isContentEditable = target.isContentEditable
      if (
        e.key === 'Enter' &&
        !e.shiftKey &&
        !isTextarea &&
        !isContentEditable &&
        currentStep < activeSteps.length - 1
      ) {
        e.preventDefault()
        nextStep()
      }
    }

    window.addEventListener('keydown', handleKeyDown)
    return () => window.removeEventListener('keydown', handleKeyDown)
  }, [currentStep, activeSteps.length, nextStep])

  // --- Closed state ---
  if (!isOpen) {
    return (
      <div className="min-h-screen bg-gradient-to-br from-background via-background to-primary/5 flex items-center justify-center p-4">
        <div className="w-full max-w-md text-center">
          <Clock className="mx-auto h-16 w-16 text-muted-foreground mb-4" />
          <h1 className="text-2xl font-bold mb-2">Applications Closed</h1>
          <p className="text-muted-foreground mb-6">
            The application period for {programName} {programYear} has ended.
            {submissionDeadline && (
              <span className="block mt-2">
                Submissions closed on{' '}
                {new Date(submissionDeadline).toLocaleDateString('en-US', {
                  dateStyle: 'long',
                })}
              </span>
            )}
          </p>
          <Button variant="outline" onClick={() => router.push('/')}>
            Return Home
          </Button>
        </div>
      </div>
    )
  }

  // --- Success state ---
  if (submitted) {
    return (
      <div className="min-h-screen bg-gradient-to-br from-background via-background to-primary/5 flex items-center justify-center p-4">
        <motion.div
          initial={{ scale: 0.8, opacity: 0 }}
          animate={{ scale: 1, opacity: 1 }}
          className="w-full max-w-md text-center"
        >
          <motion.div
            initial={{ scale: 0 }}
            animate={{ scale: 1 }}
            transition={{ delay: 0.2, type: 'spring' }}
          >
            <CheckCircle className="mx-auto h-20 w-20 text-green-500 mb-6" />
          </motion.div>
          <h1 className="text-3xl font-bold mb-4">Application Submitted!</h1>
          <p className="text-muted-foreground mb-8">{submissionMessage}</p>
          <Button onClick={() => router.push('/')}>Return Home</Button>
        </motion.div>
      </div>
    )
  }

  // --- Wizard ---
  const currentStepDef = activeSteps[currentStep]
  if (!currentStepDef) return null

  const progress = ((currentStep + 1) / activeSteps.length) * 100
  const currentStepId = currentStepDef.id as WizardStepId
  const customFields = getCustomFieldsForStep(config, currentStepId)

  // Render the appropriate step component
  function renderStep() {
    switch (currentStepId) {
      case 'welcome':
        return (
          <StepWelcome
            programName={programName}
            programYear={programYear}
            value={competitionCategory as string | null}
            onChange={(value) => form.setValue('competitionCategory', value)}
            categories={config.competitionCategories}
            welcomeMessage={config.welcomeMessage}
          />
        )
      case 'contact':
        return <StepContact form={form as UseFormReturn<any>} config={config} />
      case 'project':
        return (
          <StepProject
            form={form as UseFormReturn<any>}
            oceanIssues={config.oceanIssues}
            config={config}
          />
        )
      case 'team':
        if (config.features?.enableTeamMembers === false) return null
        return <StepTeam form={form as UseFormReturn<any>} config={config} />
      case 'additional':
        return (
          <StepAdditional
            form={form as UseFormReturn<any>}
            isBusinessConcept={isBusinessConcept}
            isStartup={isStartup}
            config={config}
          />
        )
      case 'review':
        return (
          <StepReview
            form={form as UseFormReturn<any>}
            programName={`${programName} ${programYear}`}
            config={config}
          />
        )
      default:
        return null
    }
  }

  return (
    <div className="min-h-screen bg-gradient-to-br from-background via-background to-primary/5">
      {/* Sticky header */}
      <header className="sticky top-0 z-50 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
        <div className="mx-auto max-w-4xl px-4 py-4">
          <div className="flex items-center justify-between">
            <div className="flex items-center gap-3">
              <div className="flex h-10 w-10 items-center justify-center rounded-lg bg-primary/10">
                <Waves className="h-5 w-5 text-primary" />
              </div>
              <div>
                <h1 className="font-semibold">
                  {programName} {programYear}
                </h1>
                <p className="text-xs text-muted-foreground">Application</p>
              </div>
            </div>
            <div className="text-right">
              <span className="text-sm text-muted-foreground">
                Step {currentStep + 1} of {activeSteps.length}
              </span>
            </div>
          </div>

          {/* Progress bar */}
          <div className="mt-4 h-1 sm:h-1.5 w-full overflow-hidden rounded-full bg-muted">
            <motion.div
              className="h-full bg-gradient-to-r from-primary to-primary/70"
              initial={{ width: 0 }}
              animate={{ width: `${progress}%` }}
              transition={{ duration: 0.3 }}
            />
          </div>

          {/* Step indicators (hidden on mobile) */}
          <div className="mt-3 hidden sm:flex justify-between">
            {activeSteps.map((step, index) => (
              <button
                key={step.id}
                type="button"
                onClick={() => {
                  if (index < currentStep) {
                    setDirection(index < currentStep ? -1 : 1)
                    setCurrentStep(index)
                  }
                }}
                disabled={index > currentStep}
                className={cn(
                  'text-xs font-medium transition-colors',
                  index === currentStep && 'text-primary',
                  index < currentStep &&
                    'text-muted-foreground hover:text-foreground cursor-pointer',
                  index > currentStep && 'text-muted-foreground/50'
                )}
              >
                {step.title}
              </button>
            ))}
          </div>
        </div>
      </header>

      {/* Main content */}
      <main className="mx-auto max-w-3xl px-4 py-8">
        <form onSubmit={handleSubmit(handleFormSubmit)}>
          <div className="relative min-h-[400px] sm:min-h-[500px]">
            <AnimatePresence initial={false} custom={direction} mode="wait">
              <motion.div
                key={currentStep}
                custom={direction}
                variants={variants}
                initial="enter"
                animate="center"
                exit="exit"
                transition={{
                  x: { type: 'spring', stiffness: 300, damping: 30 },
                  opacity: { duration: 0.2 },
                }}
                className="w-full"
              >
                {renderStep()}

                {/* Custom fields for this step */}
                {customFields.length > 0 && (
                  <div className="mt-6 space-y-4 mx-auto max-w-md">
                    {customFields.map((field) => (
                      <CustomFieldRenderer key={field.id} field={field} form={form} />
                    ))}
                  </div>
                )}
              </motion.div>
            </AnimatePresence>
          </div>

          {/* Navigation buttons */}
          <div className="mt-8 flex items-center justify-between border-t pt-6">
            <Button
              type="button"
              variant="ghost"
              onClick={prevStep}
              disabled={currentStep === 0 || isSubmitting}
              className={cn(
                'h-11 sm:h-10',
                currentStep === 0 && 'invisible'
              )}
            >
              <ArrowLeft className="mr-2 h-4 w-4" />
              Back
            </Button>

            {currentStep < activeSteps.length - 1 ? (
              <Button
                type="button"
                onClick={nextStep}
                className="h-11 sm:h-10"
              >
                Continue
                <ArrowRight className="ml-2 h-4 w-4" />
              </Button>
            ) : (
              <Button
                type="submit"
                disabled={isSubmitting}
                className="h-11 sm:h-10"
              >
                {isSubmitting ? (
                  <>
                    <Loader2 className="mr-2 h-4 w-4 animate-spin" />
                    Submitting...
                  </>
                ) : (
                  <>
                    <CheckCircle className="mr-2 h-4 w-4" />
                    Submit Application
                  </>
                )}
              </Button>
            )}
          </div>
        </form>
      </main>

      {/* Deadline footer */}
      {submissionDeadline && (
        <footer className="fixed bottom-0 left-0 right-0 border-t bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60 py-3 pb-[max(0.75rem,env(safe-area-inset-bottom))] sm:relative sm:static sm:mt-8 sm:pb-3">
          <div className="mx-auto max-w-3xl px-4 text-center text-sm text-muted-foreground">
            <Clock className="inline-block mr-1 h-4 w-4" />
            Applications due by{' '}
            {new Date(submissionDeadline).toLocaleDateString('en-US', {
              dateStyle: 'long',
            })}
          </div>
        </footer>
      )}
    </div>
  )
}
