<script setup lang="ts">
import { watchDebounced } from '@vueuse/core'
import { useForm } from 'vee-validate'
import { toTypedSchema } from '@vee-validate/zod'
import { useDisplay } from 'vuetify'
import { apiClient } from '@/lib/axios'
import { useAuthStore } from '@/stores/useAuthStore'
import { usePortalStore } from '@/stores/usePortalStore'
import { useRegistrationData, useSubmitRegistration } from '@/composables/api/useVolunteerRegistration'
import { fullRegistrationSchema } from '@/schemas/registrationSchema'
import type {
  RegistrationField,
  RegistrationFieldType,
  SectionOption,
  SectionPreference,
  TimeSlotOption,
  VolunteerAvailability,
  VolunteerRegistrationForm,
} from '@/types/registration'

definePage({
  name: 'volunteer-register',
  meta: {
    layout: 'portal',
    requiresAuth: false,
    navMode: 'platform',
  },
})

const route = useRoute('volunteer-register')
const router = useRouter()
const authStore = useAuthStore()
const portalStore = usePortalStore()
const { mdAndUp } = useDisplay()

const eventSlug = computed(() => route.params.eventSlug as string)
const { data: registrationData, isLoading, isError } = useRegistrationData(eventSlug)
const { mutateAsync: submitRegistration, isPending: isSubmitting } = useSubmitRegistration()

const currentStep = ref(0)
const submitError = ref<string | null>(null)
const fieldFormData = ref<Record<string, unknown>>({})
const fieldErrors = ref<Record<string, string>>({})

// Email existence check (privacy-safe — only shows boolean)
const emailExists = ref<boolean | null>(null)
const emailChecking = ref(false)
const lastCheckedEmail = ref('')
let checkEmailRequestSeq = 0

const { errors, defineField, validateField, setFieldValue, setFieldError } = useForm({
  validationSchema: toTypedSchema(fullRegistrationSchema),
  initialValues: {
    first_name: '',
    last_name: '',
    email: '',
    date_of_birth: '',
    phone: '',
  },
})

const [firstName] = defineField('first_name')
const [lastName] = defineField('last_name')
const [dateOfBirth] = defineField('date_of_birth')
const [email] = defineField('email')
const [phone] = defineField('phone')

// Pre-fill authenticated user data
watch(() => authStore.user, user => {
  if (user) {
    setFieldValue('first_name', user.first_name)
    setFieldValue('last_name', user.last_name)
    setFieldValue('email', user.email)
  }
}, { immediate: true })

function isEmailFormatForCheck(value: string): boolean {
  return value.includes('@') && value.includes('.')
}

async function runCheckEmail(rawEmail: string): Promise<void> {
  if (authStore.isAuthenticated) return

  const trimmed = rawEmail.trim()
  if (!isEmailFormatForCheck(trimmed)) {
    emailExists.value = null
    lastCheckedEmail.value = ''
    emailChecking.value = false

    return
  }

  const seq = ++checkEmailRequestSeq
  emailChecking.value = true
  try {
    const { data } = await apiClient.post<{ exists: boolean }>('/public/check-email', { email: trimmed })
    if (seq !== checkEmailRequestSeq) return
    emailExists.value = data.exists
    lastCheckedEmail.value = trimmed
  }
  catch {
    if (seq !== checkEmailRequestSeq) return
    emailExists.value = null
  }
  finally {
    if (seq === checkEmailRequestSeq)
      emailChecking.value = false
  }
}

function onEmailBlur(): void {
  if (authStore.isAuthenticated) return

  const trimmed = (email.value ?? '').trim()
  if (!isEmailFormatForCheck(trimmed)) return
  if (emailChecking.value) return
  if (trimmed === lastCheckedEmail.value && emailExists.value !== null) return

  void runCheckEmail(trimmed)
}

watchDebounced(
  email,
  val => {
    void runCheckEmail(val ?? '')
  },
  { debounce: 500 },
)

watch(email, val => {
  if (authStore.isAuthenticated) return
  const t = (val ?? '').trim()
  if (t !== lastCheckedEmail.value) {
    emailExists.value = null
  }
})

const selectedSectionIds = ref<string[]>([])
const selectedTimeSlotIds = ref<string[]>([])
const timeSlotPreferences = ref<Record<string, number>>({})

const showSections = computed(() => Boolean(registrationData.value?.event.registration_show_section_preferences))
const showAvailability = computed(() => Boolean(registrationData.value?.event.registration_show_availability))

const steps = computed(() => {
  const list = [
    { title: 'Over jou', subtitle: 'Vul je persoonlijke gegevens in' },
    { title: 'Extra informatie', subtitle: 'Antwoord op de vragen van de organisatie' },
  ]
  if (showSections.value)
    list.push({ title: 'Secties', subtitle: 'Waar wil je het liefst werken?' })
  if (showAvailability.value)
    list.push({ title: 'Beschikbaarheid', subtitle: 'Wanneer kun je helpen?' })

  return list
})

const sectionsStepIndex = computed(() => (showSections.value ? 2 : -1))
const availabilityStepIndex = computed(() => {
  if (!showAvailability.value) return -1

  return showSections.value ? 3 : 2
})

const currentStepKind = computed(() => {
  if (currentStep.value === 0) return 'personal'
  if (currentStep.value === 1) return 'dynamic'
  if (sectionsStepIndex.value !== -1 && currentStep.value === sectionsStepIndex.value) return 'sections'
  if (availabilityStepIndex.value !== -1 && currentStep.value === availabilityStepIndex.value) return 'availability'

  return 'personal'
})

const registrationFieldsList = computed(() => registrationData.value?.registration_fields ?? [])

function defaultFieldValue(type: RegistrationFieldType): unknown {
  switch (type) {
    case 'multiselect':
    case 'checkbox':
    case 'tag_picker':
      return []
    case 'boolean':
      return false
    case 'number':
    case 'heading':
      return null
    default:
      return ''
  }
}

watch(registrationFieldsList, fields => {
  for (const f of fields) {
    if (f.field_type === 'heading') continue
    if (!(f.slug in fieldFormData.value))
      fieldFormData.value[f.slug] = defaultFieldValue(f.field_type)
  }
}, { immediate: true })

watch(steps, s => {
  if (currentStep.value >= s.length)
    currentStep.value = Math.max(0, s.length - 1)
})

// Section helpers
const sectionsByCategory = computed(() => {
  if (!registrationData.value?.sections) return {}

  return registrationData.value.sections.reduce((groups, section) => {
    const cat = section.category || 'Overig'
    if (!groups[cat]) groups[cat] = []
    groups[cat].push(section)

    return groups
  }, {} as Record<string, SectionOption[]>)
})

function isSelected(sectionId: string) {
  return selectedSectionIds.value.includes(sectionId)
}

function getSelectionPriority(sectionId: string) {
  return selectedSectionIds.value.indexOf(sectionId) + 1
}

const selectedCount = computed(() => selectedSectionIds.value.length)

// Computed
const timeSlotsByDate = computed(() => {
  if (!registrationData.value?.time_slots) return []
  const groups = new Map<string, TimeSlotOption[]>()

  for (const slot of registrationData.value.time_slots) {
    if (!groups.has(slot.date)) groups.set(slot.date, [])
    groups.get(slot.date)!.push(slot)
  }

  return Array.from(groups.entries()).sort(([a], [b]) => a.localeCompare(b))
})

const totalSelectedHours = computed(() => {
  if (!registrationData.value?.time_slots) return 0

  const total = registrationData.value.time_slots
    .filter(s => selectedTimeSlotIds.value.includes(s.id))
    .reduce((sum, s) => sum + Number(s.duration_hours), 0)

  return Math.round(total * 100) / 100
})

const formattedDates = computed(() => {
  if (!registrationData.value) return ''

  return formatDateRange(
    registrationData.value.event.start_date,
    registrationData.value.event.end_date,
  )
})

const personalFieldKeys = ['first_name', 'last_name', 'date_of_birth', 'email', 'phone'] as const

function isMultiValueType(t: RegistrationFieldType): boolean {
  return t === 'multiselect' || t === 'checkbox' || t === 'tag_picker'
}

function groupedTagItems(tags: Array<{ id: string; name: string; category: string | null }>) {
  const items: Array<{ type?: string; title: string; value?: string }> = []
  let lastCategory: string | null = null

  for (const tag of tags) {
    if (tag.category !== lastCategory) {
      items.push({ type: 'subheader', title: tag.category ?? 'Overig' })
      lastCategory = tag.category
    }
    items.push({ title: tag.name, value: tag.id })
  }

  return items
}

function isEmptyFieldValue(value: unknown, type: RegistrationFieldType): boolean {
  if (value === undefined || value === null) return true
  if (value === '') return true
  if (type === 'number' && (typeof value !== 'number' || Number.isNaN(value))) return true
  if (isMultiValueType(type)) {
    if (!Array.isArray(value)) return true

    return value.length === 0
  }

  return false
}

function ensureCheckboxArray(slug: string): string[] {
  const v = fieldFormData.value[slug]
  if (Array.isArray(v)) return v.map(String)
  fieldFormData.value[slug] = []

  return fieldFormData.value[slug] as string[]
}

function toggleCheckboxOption(slug: string, option: string, checked: boolean | null) {
  const arr = ensureCheckboxArray(slug)
  const on = Boolean(checked)
  if (on) {
    if (!arr.includes(option)) arr.push(option)
  }
  else {
    const i = arr.indexOf(option)
    if (i !== -1) arr.splice(i, 1)
  }
  fieldFormData.value[slug] = [...arr]
}

function isCheckboxChecked(slug: string, option: string): boolean {
  const v = fieldFormData.value[slug]

  return Array.isArray(v) && v.includes(option)
}

function numberFieldModel(slug: string): string {
  const v = fieldFormData.value[slug]
  if (v === null || v === undefined) return ''
  if (typeof v === 'number' && Number.isNaN(v)) return ''

  return String(v)
}

function onNumberFieldInput(slug: string, raw: string) {
  if (raw === '' || raw === '-') {
    fieldFormData.value[slug] = null

    return
  }
  const n = Number(raw)
  fieldFormData.value[slug] = Number.isFinite(n) ? n : null
}

function validateDynamicFields(): boolean {
  fieldErrors.value = {}
  let firstErrorSlug: string | null = null
  for (const field of registrationFieldsList.value) {
    if (field.field_type === 'heading' || !field.is_required) continue
    const val = fieldFormData.value[field.slug]
    if (isEmptyFieldValue(val, field.field_type)) {
      fieldErrors.value[field.slug] = 'Dit veld is verplicht.'
      firstErrorSlug ??= field.slug
    }
  }
  if (firstErrorSlug) {
    nextTick(() => {
      document.getElementById(`reg-field-${firstErrorSlug}`)?.scrollIntoView({ behavior: 'smooth', block: 'center' })
    })

    return false
  }

  return true
}

async function validateCurrentStep(): Promise<boolean> {
  const k = currentStepKind.value
  if (k === 'personal') {
    const results = await Promise.all(personalFieldKeys.map(f => validateField(f)))

    return results.every(r => r.valid)
  }
  if (k === 'dynamic')
    return validateDynamicFields()

  return true
}

async function nextStep() {
  if (await validateCurrentStep()) {
    if (currentStep.value < steps.value.length - 1) currentStep.value++
  }
}

function prevStep() {
  if (currentStep.value > 0) currentStep.value--
}

function goToStep(index: number) {
  if (index < currentStep.value) {
    currentStep.value = index
  }
}

function toggleSection(sectionId: string) {
  const idx = selectedSectionIds.value.indexOf(sectionId)
  if (idx !== -1) {
    selectedSectionIds.value.splice(idx, 1)
  }
  else if (selectedSectionIds.value.length < 5) {
    selectedSectionIds.value.push(sectionId)
  }
}

// Time slot toggle
function toggleTimeSlot(slotId: string) {
  const idx = selectedTimeSlotIds.value.indexOf(slotId)
  if (idx >= 0) {
    selectedTimeSlotIds.value.splice(idx, 1)
    delete timeSlotPreferences.value[slotId]
  }
  else {
    selectedTimeSlotIds.value.push(slotId)
    timeSlotPreferences.value[slotId] = 3
  }
}

// Helpers
function formatDate(dateStr: string): string {
  return new Date(`${dateStr}T00:00:00`).toLocaleDateString('nl-NL', {
    weekday: 'long',
    day: 'numeric',
    month: 'long',
  })
}

function formatDateRange(start: string, end: string): string {
  const startDate = new Date(`${start}T00:00:00`)
  const endDate = new Date(`${end}T00:00:00`)

  if (startDate.getMonth() === endDate.getMonth() && startDate.getFullYear() === endDate.getFullYear()) {
    return `${startDate.getDate()} – ${endDate.toLocaleDateString('nl-NL', { day: 'numeric', month: 'long', year: 'numeric' })}`
  }

  return `${startDate.toLocaleDateString('nl-NL', { day: 'numeric', month: 'long' })} – ${endDate.toLocaleDateString('nl-NL', { day: 'numeric', month: 'long', year: 'numeric' })}`
}

function formatTimeRange(start: string, end: string): string {
  return `${start.slice(0, 5)} – ${end.slice(0, 5)}`
}

function buildFieldValuesPayload(): Record<string, unknown> | undefined {
  const out: Record<string, unknown> = {}
  for (const field of registrationFieldsList.value) {
    if (field.field_type === 'heading') continue
    const val = fieldFormData.value[field.slug]
    if (field.field_type === 'boolean') {
      if (typeof val === 'boolean')
        out[field.slug] = val
      continue
    }
    if (val !== undefined && val !== null && val !== '') {
      if (Array.isArray(val) && val.length === 0) continue
      out[field.slug] = val
    }
  }

  return Object.keys(out).length ? out : undefined
}

function isPersonalFieldKey(key: string): key is typeof personalFieldKeys[number] {
  return (personalFieldKeys as readonly string[]).includes(key)
}

function applyServerValidationErrors(serverErrors: Record<string, string[]>) {
  fieldErrors.value = {}
  for (const [key, msgs] of Object.entries(serverErrors)) {
    const m = /^field_values\.(.+)$/.exec(key)
    if (m?.[1]) {
      fieldErrors.value[m[1]] = msgs[0] ?? 'Ongeldige waarde.'

      continue
    }
    if (isPersonalFieldKey(key))
      setFieldError(key, msgs[0] ?? 'Ongeldige waarde.')
  }
}

async function onSubmit() {
  submitError.value = null
  fieldErrors.value = {}

  const rPersonal = await Promise.all(personalFieldKeys.map(f => validateField(f)))
  if (!rPersonal.every(x => x.valid)) {
    currentStep.value = 0

    return
  }
  if (!validateDynamicFields()) {
    currentStep.value = 1

    return
  }

  if (!registrationData.value) return

  const field_values = buildFieldValuesPayload()

  const section_preferences: SectionPreference[] | undefined
    = showSections.value && selectedSectionIds.value.length > 0
      ? selectedSectionIds.value.map((sectionId, index) => ({
          festival_section_id: sectionId,
          priority: index + 1,
        }))
      : undefined

  const availabilities: VolunteerAvailability[] = selectedTimeSlotIds.value.map(id => ({
    time_slot_id: id,
    preference_level: timeSlotPreferences.value[id] ?? 3,
  }))

  const payload: VolunteerRegistrationForm = {
    first_name: firstName.value ?? '',
    last_name: lastName.value ?? '',
    date_of_birth: dateOfBirth.value ?? '',
    email: email.value ?? '',
    phone: phone.value ?? '',
    availabilities,
  }

  if (field_values) payload.field_values = field_values
  if (section_preferences?.length) payload.section_preferences = section_preferences

  try {
    await submitRegistration({
      eventId: registrationData.value.event.id,
      form: payload,
    })

    const ev = registrationData.value.event
    portalStore.savePendingEventFromRegistration({
      event_id: ev.id,
      event_name: ev.name,
      organisation_name: '',
      organisation_id: ev.organisation_id,
      person_status: 'pending',
      start_date: ev.start_date,
      end_date: ev.end_date,
    })

    router.push({
      path: '/register/success',
      query: {
        event: registrationData.value.event.name,
        banner: registrationData.value.event.registration_banner_url ?? '',
        authenticated: authStore.isAuthenticated ? '1' : '0',
      },
    })
  }
  catch (error: unknown) {
    const axiosError = error as { response?: { status?: number; data?: { errors?: Record<string, string[]> } } }

    if (axiosError.response?.status === 422) {
      const serverErrors = axiosError.response.data?.errors

      if (serverErrors) {
        applyServerValidationErrors(serverErrors)
        const keys = Object.keys(serverErrors)
        if (keys.some(k => isPersonalFieldKey(k))) {
          currentStep.value = 0

          return
        }
        if (keys.some(k => k.startsWith('field_values.'))) {
          currentStep.value = 1

          return
        }
        if (keys.some(k => k.startsWith('section_preferences'))) {
          if (sectionsStepIndex.value !== -1) currentStep.value = sectionsStepIndex.value

          return
        }
      }
      submitError.value = 'Er zijn validatiefouten gevonden. Controleer je invoer.'
    }
    else {
      submitError.value = 'Er is een fout opgetreden. Probeer het opnieuw.'
    }
  }
}
</script>

<template>
  <!-- Loading -->
  <div
    v-if="isLoading"
    class="d-flex align-center justify-center"
    style="min-block-size: 100dvh;"
  >
    <VCard
      flat
      :max-width="500"
      class="pa-12 text-center"
    >
      <VProgressCircular
        indeterminate
        color="primary"
        size="48"
        class="mb-4"
      />
      <p class="text-body-1 text-medium-emphasis mb-0">
        Registratieformulier laden...
      </p>
    </VCard>
  </div>

  <!-- Error / Not available -->
  <div
    v-else-if="isError || !registrationData"
    class="d-flex align-center justify-center"
    style="min-block-size: 100dvh;"
  >
    <VCard
      flat
      :max-width="500"
      class="text-center pa-8"
    >
      <VIcon
        icon="tabler-calendar-off"
        size="64"
        color="warning"
        class="mb-4"
      />
      <h4 class="text-h5 mb-2">
        Niet beschikbaar
      </h4>
      <p class="text-body-1 text-medium-emphasis mb-6">
        Dit evenement accepteert momenteel geen aanmeldingen.
      </p>
      <VBtn
        to="/"
        variant="outlined"
      >
        Terug naar startpagina
      </VBtn>
    </VCard>
  </div>

  <!-- Registration page -->
  <div v-else>
    <!-- Hero banner -->
    <div
      v-if="registrationData.event.registration_banner_url"
      class="registration-banner"
    >
      <VImg
        :src="registrationData.event.registration_banner_url"
        height="220"
        cover
        gradient="to bottom, rgba(0,0,0,0.1), rgba(0,0,0,0.55)"
      >
        <div class="d-flex flex-column align-center justify-end fill-height pa-6 text-white">
          <img
            v-if="registrationData.event.registration_logo_url"
            :src="registrationData.event.registration_logo_url"
            height="48"
            class="mb-2 rounded"
          >
          <h2 class="text-h4 font-weight-bold text-center">
            {{ registrationData.event.name }}
          </h2>
          <p class="text-subtitle-1 mb-0">
            {{ formattedDates }}
          </p>
        </div>
      </VImg>
    </div>

    <!-- Fallback header when no banner -->
    <div
      v-else
      class="d-flex flex-column align-center pa-8"
      style="background: rgb(var(--v-theme-primary));"
    >
      <img
        v-if="registrationData.event.registration_logo_url"
        :src="registrationData.event.registration_logo_url"
        height="48"
        class="mb-2 rounded"
      >
      <h2 class="text-h4 font-weight-bold text-white text-center">
        {{ registrationData.event.name }}
      </h2>
      <p
        class="text-subtitle-1 mb-0"
        style="color: rgba(255,255,255,0.7);"
      >
        {{ formattedDates }}
      </p>
    </div>

    <!-- Content container -->
    <VContainer
      class="registration-container"
      :class="{ 'mt-n8': registrationData.event.registration_banner_url }"
    >
      <!-- Welcome text -->
      <VCard
        v-if="registrationData.event.registration_welcome_text"
        class="mb-4 pa-5"
        variant="flat"
      >
        <p class="text-body-1 mb-0">
          {{ registrationData.event.registration_welcome_text }}
        </p>
      </VCard>

      <!-- Auth info / Login hint -->
      <VAlert
        v-if="authStore.isAuthenticated"
        type="info"
        variant="tonal"
        class="mb-4"
      >
        Je bent ingelogd als {{ authStore.user?.full_name }}. Je gegevens zijn automatisch ingevuld.
      </VAlert>

      <div
        v-else
        class="text-body-2 text-medium-emphasis mb-4"
      >
        Al een account?
        <RouterLink
          to="/login"
          class="text-primary font-weight-medium"
        >
          Log in
        </RouterLink>
        om je gegevens automatisch in te vullen.
      </div>

      <!-- Submit error -->
      <VAlert
        v-if="submitError"
        type="error"
        variant="tonal"
        class="mb-4"
        closable
        @click:close="submitError = null"
      >
        {{ submitError }}
      </VAlert>

      <!-- Wizard -->
      <VRow no-gutters>
        <!-- Desktop: vertical step navigation -->
        <VCol
          v-if="mdAndUp"
          cols="12"
          md="4"
        >
          <div class="pa-5 pt-8">
            <div
              class="d-flex flex-column"
              style="gap: 28px;"
            >
              <div
                v-for="(step, index) in steps"
                :key="index"
                class="d-flex align-center ga-4"
                :class="{ 'cursor-pointer': index < currentStep }"
                @click="index < currentStep && goToStep(index)"
              >
                <!-- Number square -->
                <div
                  class="d-flex align-center justify-center flex-shrink-0"
                  :style="{
                    width: '50px',
                    height: '50px',
                    borderRadius: '10px',
                    fontSize: '18px',
                    fontWeight: 700,
                    backgroundColor: index === currentStep
                      ? 'rgb(var(--v-theme-primary))'
                      : index < currentStep
                        ? 'rgba(var(--v-theme-primary), 0.16)'
                        : 'rgba(var(--v-theme-on-surface), 0.08)',
                    color: index === currentStep
                      ? 'white'
                      : index < currentStep
                        ? 'rgb(var(--v-theme-primary))'
                        : 'rgba(var(--v-theme-on-surface), 0.4)',
                    transition: 'all 0.2s ease',
                  }"
                >
                  <VIcon
                    v-if="index < currentStep"
                    size="22"
                  >
                    tabler-check
                  </VIcon>
                  <span v-else>{{ index + 1 }}</span>
                </div>

                <!-- Step text -->
                <div>
                  <div
                    :class="{
                      'text-body-1 font-weight-bold': index === currentStep,
                      'text-body-1 font-weight-medium': index !== currentStep,
                    }"
                    :style="index > currentStep
                      ? 'color: rgba(var(--v-theme-on-surface), 0.4)'
                      : index < currentStep
                        ? 'color: rgba(var(--v-theme-on-surface), 0.5)'
                        : ''
                    "
                  >
                    {{ step.title }}
                  </div>
                  <div
                    class="text-caption"
                    :style="{
                      color: index === currentStep
                        ? 'rgba(var(--v-theme-on-surface), 0.5)'
                        : 'rgba(var(--v-theme-on-surface), 0.35)',
                    }"
                  >
                    {{ step.subtitle }}
                  </div>
                </div>
              </div>
            </div>
          </div>
        </VCol>

        <!-- Mobile: horizontal chips -->
        <VCol
          v-if="!mdAndUp"
          cols="12"
        >
          <VCard
            variant="flat"
            rounded="lg"
            class="mb-4"
          >
            <div class="d-flex justify-center flex-wrap ga-2 pa-4">
              <VChip
                v-for="(step, index) in steps"
                :key="index"
                :color="index === currentStep ? 'primary' : index < currentStep ? 'success' : 'default'"
                :variant="index === currentStep ? 'flat' : 'tonal'"
                size="small"
              >
                <VIcon
                  v-if="index < currentStep"
                  start
                  size="14"
                >
                  tabler-check
                </VIcon>
                <span>{{ index + 1 }}. {{ step.title }}</span>
              </VChip>
            </div>
          </VCard>
        </VCol>

        <!-- Step content -->
        <VCol
          cols="12"
          :md="mdAndUp ? 8 : 12"
        >
          <VCard
            variant="flat"
            rounded="lg"
            class="h-100"
          >
            <VCardText class="pa-8">
              <!-- Step header -->
              <div class="mb-6">
                <p class="text-caption text-medium-emphasis mb-1">
                  Deel {{ currentStep + 1 }} van {{ steps.length }}
                </p>
                <h5 class="text-h5 mb-1">
                  {{ steps[currentStep].title }}
                </h5>
                <p class="text-body-2 text-medium-emphasis mb-0">
                  {{ steps[currentStep].subtitle }}
                </p>
              </div>

              <!-- Step 0: Over jou + contact -->
              <div v-show="currentStep === 0">
                <VRow>
                  <VCol
                    cols="12"
                    md="6"
                  >
                    <label
                      class="text-body-2 d-block mb-1 text-high-emphasis"
                      for="volunteer-reg-first-name"
                    >
                      Voornaam <span class="text-error">*</span>
                    </label>
                    <VTextField
                      id="volunteer-reg-first-name"
                      v-model="firstName"
                      variant="outlined"
                      placeholder="Je voornaam"
                      :error-messages="errors.first_name"
                      density="comfortable"
                      hide-details="auto"
                    />
                  </VCol>

                  <VCol
                    cols="12"
                    md="6"
                  >
                    <label
                      class="text-body-2 d-block mb-1 text-high-emphasis"
                      for="volunteer-reg-last-name"
                    >
                      Achternaam <span class="text-error">*</span>
                    </label>
                    <VTextField
                      id="volunteer-reg-last-name"
                      v-model="lastName"
                      variant="outlined"
                      placeholder="Je achternaam"
                      :error-messages="errors.last_name"
                      density="comfortable"
                      hide-details="auto"
                    />
                  </VCol>

                  <VCol
                    cols="12"
                    md="6"
                  >
                    <label
                      class="text-body-2 d-block mb-1 text-high-emphasis"
                      for="volunteer-reg-dob"
                    >
                      Geboortedatum
                    </label>
                    <VTextField
                      id="volunteer-reg-dob"
                      v-model="dateOfBirth"
                      class="volunteer-reg-dob-field"
                      variant="outlined"
                      type="date"
                      :error-messages="errors.date_of_birth"
                      density="comfortable"
                      hide-details="auto"
                    >
                      <template #prepend-inner>
                        <VIcon
                          icon="tabler-calendar"
                          size="20"
                        />
                      </template>
                    </VTextField>
                  </VCol>
                </VRow>

                <hr class="my-6 mx-n6">

                <h6 class="text-h6 mb-2">
                  Contactgegevens
                </h6>
                <p class="text-body-2 text-medium-emphasis mb-6">
                  Vul deze gegevens zorgvuldig in: we gebruiken ze om alle informatie over het evenement naar je te versturen.
                </p>

                <VRow>
                  <VCol cols="12">
                    <label
                      class="text-body-2 d-block mb-1 text-high-emphasis"
                      for="volunteer-reg-email"
                    >
                      E-mailadres <span class="text-error">*</span>
                    </label>
                    <VTextField
                      id="volunteer-reg-email"
                      v-model="email"
                      variant="outlined"
                      type="email"
                      placeholder="je@email.nl"
                      prepend-inner-icon="tabler-mail"
                      :error-messages="errors.email"
                      :disabled="authStore.isAuthenticated"
                      density="comfortable"
                      hide-details="auto"
                      @blur="onEmailBlur"
                    >
                      <template
                        v-if="!authStore.isAuthenticated && emailChecking"
                        #append-inner
                      >
                        <VProgressCircular
                          indeterminate
                          color="primary"
                          size="20"
                          width="2"
                        />
                      </template>
                    </VTextField>
                  </VCol>

                  <!-- Existing account notice -->
                  <VCol
                    v-if="!authStore.isAuthenticated && emailExists === true"
                    cols="12"
                  >
                    <VAlert
                      type="info"
                      variant="tonal"
                    >
                      <template #title>
                        Er bestaat al een account met dit e-mailadres
                      </template>
                      <template #text>
                        <p class="mb-2">
                          Als je al eerder bij een evenement betrokken bent geweest,
                          kun je inloggen om je registratie automatisch te koppelen
                          aan je bestaande account.
                        </p>
                        <VBtn
                          size="small"
                          variant="tonal"
                          color="primary"
                          :to="`/login?to=/register/${eventSlug}`"
                        >
                          Inloggen en registreren
                        </VBtn>
                        <p class="text-caption text-medium-emphasis mt-2 mb-0">
                          Je kunt ook gewoon doorgaan met registreren — we koppelen
                          je registratie later aan je account.
                        </p>
                      </template>
                    </VAlert>
                  </VCol>

                  <VCol cols="12">
                    <label
                      class="text-body-2 d-block mb-1 text-high-emphasis"
                      for="volunteer-reg-phone"
                    >
                      Telefoonnummer
                    </label>
                    <VTextField
                      id="volunteer-reg-phone"
                      v-model="phone"
                      variant="outlined"
                      placeholder="06 12345678"
                      prepend-inner-icon="tabler-phone"
                      :error-messages="errors.phone"
                      density="comfortable"
                      hide-details="auto"
                    />
                  </VCol>
                </VRow>
              </div>

              <!-- Step 1: Extra informatie (dynamic registration_fields) -->
              <div v-show="currentStep === 1">
                  <VRow>
                    <template
                      v-for="(field, fieldIndex) in registrationFieldsList"
                      :key="field.id"
                    >
                    <!-- HEADING field: full-width section header -->
                    <VCol
                      v-if="field.field_type === 'heading'"
                      cols="12"
                      :class="fieldIndex === 0 ? '' : 'mt-4'"
                    >
                      <div class="text-subtitle-1 font-weight-medium mb-1">
                        {{ field.label }}
                      </div>
                      <div
                        v-if="field.help_text"
                        class="text-body-2 text-medium-emphasis mb-3"
                      >
                        {{ field.help_text }}
                      </div>
                      <VDivider class="mb-2" />
                    </VCol>

                    <!-- Regular input field -->
                    <VCol
                      v-else
                      cols="12"
                      :md="field.display_width === 'half' ? 6 : 12"
                    >
                      <div :id="`reg-field-${field.slug}`">
                        <VTextField
                          v-if="field.field_type === 'text'"
                          v-model="fieldFormData[field.slug] as string"
                          variant="outlined"
                          density="comfortable"
                          hide-details="auto"
                          :label="field.label + (field.is_required ? ' *' : '')"
                          :hint="field.help_text ?? undefined"
                          persistent-hint
                          :error-messages="fieldErrors[field.slug]"
                        />

                        <VTextField
                          v-else-if="field.field_type === 'number'"
                          :model-value="numberFieldModel(field.slug)"
                          variant="outlined"
                          type="number"
                          density="comfortable"
                          hide-details="auto"
                          :label="field.label + (field.is_required ? ' *' : '')"
                          :hint="field.help_text ?? undefined"
                          persistent-hint
                          :error-messages="fieldErrors[field.slug]"
                          @update:model-value="(v: string | number | null) => onNumberFieldInput(field.slug, String(v ?? ''))"
                        />

                        <VTextarea
                          v-else-if="field.field_type === 'textarea'"
                          v-model="fieldFormData[field.slug] as string"
                          variant="outlined"
                          rows="3"
                          auto-grow
                          density="comfortable"
                          hide-details="auto"
                          :label="field.label + (field.is_required ? ' *' : '')"
                          :hint="field.help_text ?? undefined"
                          persistent-hint
                          :error-messages="fieldErrors[field.slug]"
                        />

                        <VSelect
                          v-else-if="field.field_type === 'select'"
                          v-model="fieldFormData[field.slug] as string"
                          variant="outlined"
                          density="comfortable"
                          hide-details="auto"
                          :items="field.normalized_options ?? []"
                          item-title="label"
                          item-value="label"
                          :label="field.label + (field.is_required ? ' *' : '')"
                          :hint="field.help_text ?? undefined"
                          persistent-hint
                          :error-messages="fieldErrors[field.slug]"
                          :clearable="!field.is_required"
                        >
                          <template #item="{ props: itemProps, item }">
                            <VListItem v-bind="itemProps">
                              <template
                                v-if="item.raw.description"
                                #subtitle
                              >
                                {{ item.raw.description }}
                              </template>
                            </VListItem>
                          </template>
                        </VSelect>

                        <VSelect
                          v-else-if="field.field_type === 'multiselect'"
                          v-model="fieldFormData[field.slug] as string[]"
                          variant="outlined"
                          density="comfortable"
                          hide-details="auto"
                          multiple
                          chips
                          closable-chips
                          :items="field.normalized_options ?? []"
                          item-title="label"
                          item-value="label"
                          :label="field.label + (field.is_required ? ' *' : '')"
                          :hint="field.help_text ?? undefined"
                          persistent-hint
                          :error-messages="fieldErrors[field.slug]"
                        >
                          <template #item="{ props: itemProps, item }">
                            <VListItem v-bind="itemProps">
                              <template
                                v-if="item.raw.description"
                                #subtitle
                              >
                                {{ item.raw.description }}
                              </template>
                            </VListItem>
                          </template>
                        </VSelect>

                        <div v-else-if="field.field_type === 'checkbox'">
                          <div class="text-body-2 d-block mb-1 text-high-emphasis">
                            {{ field.label }}<span v-if="field.is_required" class="text-error"> *</span>
                          </div>
                          <p
                            v-if="field.help_text"
                            class="text-caption text-medium-emphasis mb-2"
                          >
                            {{ field.help_text }}
                          </p>
                          <VCheckbox
                            v-for="opt in (field.normalized_options ?? [])"
                            :key="opt.label"
                            :model-value="isCheckboxChecked(field.slug, opt.label)"
                            density="comfortable"
                            hide-details
                            @update:model-value="(v: boolean | null) => toggleCheckboxOption(field.slug, opt.label, v)"
                          >
                            <template #label>
                              <div>
                                <span class="text-body-1">{{ opt.label }}</span>
                                <p
                                  v-if="opt.description"
                                  class="text-body-2 text-medium-emphasis mt-1 mb-0"
                                >
                                  {{ opt.description }}
                                </p>
                              </div>
                            </template>
                          </VCheckbox>
                          <div
                            v-if="fieldErrors[field.slug]"
                            class="text-caption text-error"
                          >
                            {{ fieldErrors[field.slug] }}
                          </div>
                        </div>

                        <div v-else-if="field.field_type === 'radio'">
                          <div class="text-body-2 d-block mb-1 text-high-emphasis">
                            {{ field.label }}<span v-if="field.is_required" class="text-error"> *</span>
                          </div>
                          <p
                            v-if="field.help_text"
                            class="text-caption text-medium-emphasis mb-2"
                          >
                            {{ field.help_text }}
                          </p>
                          <VRadioGroup
                            v-model="fieldFormData[field.slug] as string"
                            density="comfortable"
                            hide-details="auto"
                            :error-messages="fieldErrors[field.slug]"
                          >
                            <VRadio
                              v-for="opt in (field.normalized_options ?? [])"
                              :key="opt.label"
                              :value="opt.label"
                              density="comfortable"
                              hide-details
                            >
                              <template #label>
                                <div>
                                  <span class="text-body-1">{{ opt.label }}</span>
                                  <p
                                    v-if="opt.description"
                                    class="text-body-2 text-medium-emphasis mt-1 mb-0"
                                  >
                                    {{ opt.description }}
                                  </p>
                                </div>
                              </template>
                            </VRadio>
                          </VRadioGroup>
                        </div>

                        <VSwitch
                          v-else-if="field.field_type === 'boolean'"
                          v-model="fieldFormData[field.slug] as boolean"
                          inset
                          color="primary"
                          density="comfortable"
                          hide-details="auto"
                          :label="field.label + (field.is_required ? ' *' : '')"
                          :hint="field.help_text ?? undefined"
                          persistent-hint
                          :error-messages="fieldErrors[field.slug]"
                        />

                        <VAutocomplete
                          v-else-if="field.field_type === 'tag_picker'"
                          v-model="fieldFormData[field.slug] as string[]"
                          variant="outlined"
                          density="comfortable"
                          hide-details="auto"
                          multiple
                          chips
                          closable-chips
                          :items="groupedTagItems(field.available_tags ?? [])"
                          item-title="title"
                          item-value="value"
                          :label="field.label + (field.is_required ? ' *' : '')"
                          :hint="field.help_text ?? undefined"
                          persistent-hint
                          :error-messages="fieldErrors[field.slug]"
                        />
                      </div>
                    </VCol>
                    </template>
                  </VRow>

                <p
                  v-if="registrationFieldsList.length === 0"
                  class="text-body-2 text-medium-emphasis mb-0"
                >
                  Geen extra vragen voor dit evenement.
                </p>
              </div>

              <!-- Secties -->
              <div v-show="currentStepKind === 'sections'">
                <template
                  v-for="(sections, category) in sectionsByCategory"
                  :key="category"
                >
                  <div class="text-subtitle-2 text-medium-emphasis mt-4 mb-2">
                    {{ category }}
                  </div>

                  <VRow dense>
                    <VCol
                      v-for="section in sections"
                      :key="section.id"
                      cols="12"
                      sm="6"
                    >
                      <VCard
                        :variant="isSelected(section.id) ? 'flat' : 'outlined'"
                        :color="isSelected(section.id) ? 'primary' : undefined"
                        class="cursor-pointer"
                        :disabled="!isSelected(section.id) && selectedCount >= 5"
                        @click="toggleSection(section.id)"
                      >
                        <VCardText class="d-flex align-center ga-3 pa-3">
                          <VCheckboxBtn
                            :model-value="isSelected(section.id)"
                            readonly
                            density="compact"
                            hide-details
                          />

                          <VIcon
                            v-if="section.icon"
                            size="20"
                            :icon="section.icon"
                          />

                          <div class="flex-grow-1">
                            <div class="text-body-1 font-weight-medium">
                              {{ section.name }}
                            </div>
                            <div
                              v-if="section.registration_description"
                              class="text-body-2 text-medium-emphasis"
                            >
                              {{ section.registration_description }}
                            </div>
                          </div>

                          <VChip
                            v-if="isSelected(section.id)"
                            size="x-small"
                            color="primary"
                            variant="elevated"
                          >
                            #{{ getSelectionPriority(section.id) }}
                          </VChip>
                        </VCardText>
                      </VCard>
                    </VCol>
                  </VRow>
                </template>

                <VAlert
                  v-if="!Object.keys(sectionsByCategory).length"
                  type="info"
                  variant="tonal"
                  class="mt-4"
                >
                  Er zijn nog geen werkgebieden geconfigureerd voor dit evenement.
                </VAlert>

                <p
                  v-if="selectedCount > 0"
                  class="text-body-2 text-medium-emphasis mt-4"
                >
                  {{ selectedCount }} van 5 onderdelen geselecteerd
                </p>
              </div>

              <!-- Beschikbaarheid -->
              <div v-show="currentStepKind === 'availability'">
                <p
                  v-if="registrationData.time_slots.length === 0"
                  class="text-body-1 text-medium-emphasis"
                >
                  Er zijn geen tijdsloten beschikbaar voor dit evenement.
                </p>

                <template v-else>
                  <div
                    v-for="[date, slots] in timeSlotsByDate"
                    :key="date"
                    class="mb-6"
                  >
                    <h4 class="text-subtitle-1 font-weight-bold mb-2 text-capitalize">
                      {{ formatDate(date) }}
                    </h4>
                    <VList
                      density="compact"
                      class="registration-availability-list"
                    >
                      <VListItem
                        v-for="slot in slots"
                        :key="slot.id"
                        @click="toggleTimeSlot(slot.id)"
                      >
                        <template #prepend>
                          <VCheckboxBtn
                            :model-value="selectedTimeSlotIds.includes(slot.id)"
                            @click.stop="toggleTimeSlot(slot.id)"
                          />
                        </template>

                        <VListItemTitle>{{ slot.name }}</VListItemTitle>
                        <VListItemSubtitle>
                          {{ formatTimeRange(slot.start_time, slot.end_time) }} &middot; {{ slot.duration_hours }}u
                        </VListItemSubtitle>

                        <template
                          v-if="selectedTimeSlotIds.includes(slot.id)"
                          #append
                        >
                          <VRating
                            v-model="timeSlotPreferences[slot.id]"
                            density="compact"
                            size="small"
                            length="5"
                            color="warning"
                            active-color="warning"
                            @click.stop
                          />
                        </template>
                      </VListItem>
                    </VList>
                  </div>

                  <VDivider class="mb-4" />

                  <div class="d-flex align-center">
                    <span class="text-body-1">
                      Totaal geselecteerd: <strong>{{ totalSelectedHours }} uur</strong>
                    </span>
                  </div>

                  <VAlert
                    v-if="selectedTimeSlotIds.length > 0 && totalSelectedHours < 8"
                    type="warning"
                    variant="tonal"
                    class="mt-4"
                  >
                    Minimaal 8 uur nodig voor een festivalpas.
                  </VAlert>
                </template>
              </div>

              <!-- Navigation -->
              <VDivider class="my-6" />

              <div class="d-flex justify-space-between">
                <VBtn
                  v-if="currentStep > 0"
                  variant="outlined"
                  color="secondary"
                  @click="prevStep"
                >
                  <VIcon
                    icon="tabler-arrow-left"
                    start
                  />
                  Vorige
                </VBtn>
                <div v-else />

                <VBtn
                  v-if="currentStep < steps.length - 1"
                  color="primary"
                  @click="nextStep"
                >
                  Volgende
                  <VIcon
                    icon="tabler-arrow-right"
                    end
                  />
                </VBtn>

                <VBtn
                  v-else
                  color="success"
                  :loading="isSubmitting"
                  @click="onSubmit"
                >
                  <VIcon
                    icon="tabler-send"
                    start
                  />
                  Aanmelding versturen
                </VBtn>
              </div>
            </VCardText>
          </VCard>
        </VCol>
      </VRow>

    </VContainer>
  </div>
</template>

<style scoped>
.registration-container {
  position: relative;
  z-index: 1;
  max-inline-size: 1000px;
}

/*
  Native date inputs have a large intrinsic min-width; without min-width: 0 the
  grid cell grows and the prepend-inner icon no longer sits inside the outline
  next to the value (Vuetify v-field grid: prepend-inner | field).
*/
.volunteer-reg-dob-field :deep(.v-field__field) {
  min-inline-size: 0;
}

.volunteer-reg-dob-field :deep(input.v-field__input[type="date"]) {
  flex: 1 1 auto;
  max-inline-size: 100%;
  min-inline-size: 0;
}

/*
  Vuetify's .v-list uses overflow: auto, which shows scrollbars on this step when
  list rows are slightly wider than the card (e.g. checkbox + text + rating).
*/
.registration-availability-list {
  overflow: visible !important;
}
</style>
