<template>
  <div class="flex flex-col w-full">
    <div class="w-full p-4">
      <div class="flex flex-col gap-4 sm:gap-6 w-full">
        <div class="lch-stepper relative">
          <div
            ref="stepperScrollEl"
            :class="['lch-stepper-scroll overflow-x-auto overflow-y-visible scroll-smooth', cursorClass]"
          >
            <UStepper
              ref="stepper"
              v-model="activeStepperItemIndex"
              :items="stepperItems"
              :ui="stepperUi"
              :linear="false"
              class="w-full"
            />
          </div>

          <div
            v-if="canScrollLeft"
            class="pointer-events-none absolute inset-y-0 left-0 w-20 bg-linear-to-r from-default to-transparent"
          />
          <div
            v-if="canScrollRight"
            class="pointer-events-none absolute inset-y-0 right-0 w-20 bg-linear-to-l from-default to-transparent"
          />

          <UButton
            v-if="canScrollLeft"
            icon="i-lucide-chevron-left"
            color="neutral"
            variant="ghost"
            size="md"
            class="absolute left-1 top-1/2 -translate-y-1/2"
            aria-label="Scroll steps left"
            @click="scrollStepperBy(-1)"
          />
          <UButton
            v-if="canScrollRight"
            icon="i-lucide-chevron-right"
            color="neutral"
            variant="ghost"
            size="md"
            class="absolute right-1 top-1/2 -translate-y-1/2"
            aria-label="Scroll steps right"
            @click="scrollStepperBy(1)"
          />
        </div>
      </div>
    </div>

    <div class="w-full p-4">
      <div class="flex flex-col gap-4 sm:gap-6 w-full lg:max-w-4xl mx-auto">
        <slot />
        <h1 v-if="currentFormElementSection?.title" class="text-xl text-pretty font-bold text-highlighted">
          {{ currentFormElementSection.title }}
        </h1>

        <UCard
          v-for="{ subsection, sectionIndex } in visibleSubsections"
          :key="getSubsectionKey(currentFormElementSection, sectionIndex, subsection)"
          variant="subtle"
          class="mb-6"
        >
          <div class="mb-4">
            <h2 class="text-lg font-semibold text-highlighted">{{ subsection.title }}</h2>
            <p v-if="subsection.subtitle" class="text-sm text-dimmed">{{ subsection.subtitle }}</p>
          </div>
          <FormEngine
            :model-value="subsection.formElements"
            :visibility-map="visibilityMap"
            :application-form-id="applicationFormId"
            :disabled="disabled"
            :all-form-elements="allFormElements"
            @update:model-value="
              (elements) =>
                handleFormElementUpdate(elements, getSubsectionKey(currentFormElementSection, sectionIndex, subsection))
            "
            @add:input-form="
              (position) =>
                handleAddInputForm(position, getSubsectionKey(currentFormElementSection, sectionIndex, subsection))
            "
            @clone:element="
              (element, position) =>
                handleCloneElement(
                  element,
                  position,
                  getSubsectionKey(currentFormElementSection, sectionIndex, subsection)
                )
            "
          />
        </UCard>

        <UCard v-if="visibleSubsections.length === 0" variant="subtle" class="mb-6">
          <div class="text-center py-8 text-dimmed">
            <UIcon name="i-lucide-eye-off" class="w-12 h-12 mx-auto mb-3 opacity-50" />
            <p>{{ $t('applicationForms.noVisibleElements') }}</p>
          </div>
        </UCard>

        <div class="flex gap-2 justify-between">
          <UButton leading-icon="i-lucide-arrow-left" :disabled="!stepper?.hasPrev" @click="handleNavigate('backward')">
            {{ $t('applicationForms.navigation.previous') }}
          </UButton>

          <div class="flex flex-wrap items-center gap-1.5">
            <UButton
              trailing-icon="i-lucide-save"
              :disabled="disabled"
              variant="outline"
              size="lg"
              @click="emit('save')"
            >
              {{ $t('applicationForms.navigation.save') }}
            </UButton>
            <UButton
              v-if="stepper?.hasNext"
              trailing-icon="i-lucide-arrow-right"
              size="lg"
              @click="handleNavigate('forward')"
            >
              {{ $t('applicationForms.navigation.next') }}
            </UButton>
            <UButton
              v-if="!stepper?.hasNext"
              trailing-icon="i-lucide-send-horizontal"
              :disabled="disabled"
              size="lg"
              @click="emit('submit')"
            >
              {{ $t('applicationForms.navigation.submit') }}
            </UButton>
          </div>
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import { usePointerSwipe } from '@vueuse/core'
import type {
  ApplicationFormDto,
  FormElementSectionDto,
  FormElementDto,
  FormElementSubSectionDto
} from '~~/.api-client'

const props = defineProps<{
  formElementSections: FormElementSectionDto[]
  initialSectionIndex?: number
  applicationFormId?: string
  disabled?: boolean
}>()

const emit = defineEmits<{
  save: []
  submit: []
  'add-input-form': [updatedForm: ApplicationFormDto | undefined]
  'update:formElementSections': [sections: FormElementSectionDto[]]
  navigate: [{ direction: 'forward' | 'backward'; index: number }]
}>()

const { stepper, activeStepperItemIndex, stepperItems, currentFormElementSection, navigateStepper } = useFormStepper(
  computed(() => props.formElementSections)
)

const stepperScrollEl = ref<HTMLElement | null>(null)
const initialScrollLeft = ref(0)
const initialPointerX = ref(0)
const canScrollLeft = ref(false)
const canScrollRight = ref(false)
const hasOverflow = ref(false)

const { evaluateFormElementVisibility } = useFormElementVisibility()
const { clearHiddenFormElementValues } = useFormElementValueClearing()
const { processSpawnTriggers } = useSectionSpawning()
const { cloneElement } = useClonableElements()

const { isSwiping } = usePointerSwipe(stepperScrollEl, {
  threshold: 0,
  disableTextSelect: true,

  onSwipeStart: (e: PointerEvent) => {
    // Capture initial scroll position and pointer position when drag starts
    initialScrollLeft.value = stepperScrollEl.value?.scrollLeft ?? 0
    initialPointerX.value = e.clientX
  },

  onSwipe: (e: PointerEvent) => {
    // Calculate how far the pointer has moved from initial position
    const deltaX = initialPointerX.value - e.clientX

    // Update scroll position with direct 1:1 tracking
    const el = stepperScrollEl.value
    if (el) {
      el.scrollLeft = initialScrollLeft.value + deltaX
    }
  }
})

const previousVisibilityMap = ref<Map<string, boolean>>(new Map())

const allFormElements = computed(() => {
  return props.formElementSections
    .filter((section) => section.isTemplate !== true)
    .flatMap((section) => section.formElementSubSections?.flatMap((subsection) => subsection.formElements) ?? [])
})

const visibilityMap = computed(() => {
  return evaluateFormElementVisibility(allFormElements.value)
})

const cursorClass = computed(
  () =>
    isSwiping.value
      ? 'cursor-grabbing select-none' // During drag: closed fist + no selection
      : 'cursor-grab' // Ready to drag: open hand
)

const stepperUi = computed(() => ({
  header: hasOverflow.value ? 'flex w-full flex-nowrap' : 'flex w-full flex-nowrap justify-center',
  item: 'w-auto shrink-0 flex-[0_0_calc(100%/6)] min-w-[14rem]'
}))

const visibleSubsections = computed(() => {
  if (!currentFormElementSection.value?.formElementSubSections) {
    return []
  }

  return currentFormElementSection.value.formElementSubSections
    .map((subsection) => ({ subsection, sectionIndex: currentSectionIndex.value }))
    .filter(({ subsection }) => {
      return subsection.formElements.some((element) => {
        const key = element.id || element.reference
        return key ? visibilityMap.value.get(key) !== false : true
      })
    })
})

const currentSectionIndex = computed(() => {
  if (!currentFormElementSection.value) return -1
  return props.formElementSections.indexOf(currentFormElementSection.value)
})

onMounted(() => {
  if (props.initialSectionIndex !== undefined) {
    activeStepperItemIndex.value = props.initialSectionIndex
  }
  previousVisibilityMap.value = visibilityMap.value

  stepperScrollEl.value?.addEventListener('scroll', updateStepperOverflowIndicators, { passive: true })
  updateStepperOverflowIndicators()

  window.addEventListener('resize', scrollToActiveStep)
})

onUnmounted(() => {
  stepperScrollEl.value?.removeEventListener('scroll', updateStepperOverflowIndicators)
  window.removeEventListener('resize', scrollToActiveStep)
})

watch(
  () => activeStepperItemIndex.value,
  async () => {
    await nextTick()
    scrollToActiveStep()
  }
)

watch(
  () => stepperItems.value.length,
  async () => {
    await nextTick()
    updateStepperOverflowIndicators()
  }
)

function getActiveStepElement(): HTMLElement | null {
  const root = stepperScrollEl.value
  if (!root) return null

  const selectors = [
    // Nuxt UI / Reka often exposes state via data attributes
    '[data-state="active"]',
    '[data-active="true"]',
    // ARIA patterns
    '[aria-current="step"]',
    '[aria-selected="true"]'
  ]

  for (const selector of selectors) {
    const el = root.querySelector(selector) as HTMLElement | null
    if (!el) continue

    // Prefer the list item (stable width) if present
    const li = el.closest('li') as HTMLElement | null
    return li ?? el
  }

  return null
}

function scrollToActiveStep() {
  const scroller = stepperScrollEl.value
  if (!scroller) return

  const activeIndex = activeStepperItemIndex.value
  if (activeIndex < 3) {
    scroller.scrollTo({ left: 0, behavior: 'smooth' })
    return
  }

  const activeEl = getActiveStepElement()
  if (!activeEl) return

  const scrollerRect = scroller.getBoundingClientRect()
  const activeRect = activeEl.getBoundingClientRect()

  const activeCenterInScroller = activeRect.left - scrollerRect.left + activeRect.width / 2 + scroller.scrollLeft
  const targetScrollLeft = activeCenterInScroller - scroller.clientWidth / 2

  const maxScrollLeft = Math.max(0, scroller.scrollWidth - scroller.clientWidth)
  const clamped = Math.max(0, Math.min(maxScrollLeft, targetScrollLeft))

  scroller.scrollTo({ left: clamped, behavior: 'smooth' })
}

function updateStepperOverflowIndicators() {
  const scroller = stepperScrollEl.value
  if (!scroller) {
    canScrollLeft.value = false
    canScrollRight.value = false
    hasOverflow.value = false
    return
  }

  const maxScrollLeft = Math.max(0, scroller.scrollWidth - scroller.clientWidth)
  hasOverflow.value = maxScrollLeft > 0
  canScrollLeft.value = scroller.scrollLeft > 1
  canScrollRight.value = scroller.scrollLeft < maxScrollLeft - 1
}

function scrollStepperBy(direction: -1 | 1) {
  const scroller = stepperScrollEl.value
  if (!scroller) return

  const delta = Math.max(200, Math.round(scroller.clientWidth * 0.6))
  scroller.scrollBy({ left: direction * delta, behavior: 'smooth' })
}

async function handleAddInputForm(position: number, subsectionKey: string) {
  const foundSubsection = findSubsectionByKey(subsectionKey)
  if (!foundSubsection) return

  const { addInputFormElement } = useFormElementManagement()
  const updatedElements = addInputFormElement(foundSubsection.formElements, position)

  const updatedSections = updateSubsectionElements(props.formElementSections, subsectionKey, updatedElements)
  emit('update:formElementSections', updatedSections)
}

function findSubsectionByKey(subsectionKey: string): FormElementSubSectionDto | undefined {
  for (let sectionIdx = 0; sectionIdx < props.formElementSections.length; sectionIdx++) {
    const section = props.formElementSections[sectionIdx]
    if (!section) continue

    for (let i = 0; i < section.formElementSubSections.length; i++) {
      const subsection = section.formElementSubSections[i]
      if (subsection && getSubsectionKey(section, sectionIdx, subsection) === subsectionKey) {
        return subsection
      }
    }
  }
  return undefined
}

async function handleNavigate(direction: 'forward' | 'backward') {
  await navigateStepper(direction)
  emit('navigate', { direction, index: activeStepperItemIndex.value })
}

function handleCloneElement(element: FormElementDto, position: number, subsectionKey: string) {
  const clonedElement = cloneElement(element, allFormElements.value)

  const updatedSections = props.formElementSections.map((section, sectionIdx) => ({
    ...section,
    formElementSubSections: section.formElementSubSections.map((subsection) => {
      if (getSubsectionKey(section, sectionIdx, subsection) === subsectionKey) {
        const newFormElements = [...subsection.formElements]
        newFormElements.splice(position + 1, 0, clonedElement as FormElementDto)
        return { ...subsection, formElements: newFormElements }
      }
      return subsection
    })
  }))

  emit('update:formElementSections', updatedSections)
}

function handleFormElementUpdate(updatedFormElements: FormElementDto[], subsectionKey: string) {
  let updatedSections = updateSubsectionElements(props.formElementSections, subsectionKey, updatedFormElements)
  updatedSections = processSpawnTriggers(updatedSections, updatedFormElements)
  updatedSections = clearNewlyHiddenFormElements(updatedSections)
  emit('update:formElementSections', updatedSections)
}

function clearNewlyHiddenFormElements(sections: FormElementSectionDto[]): FormElementSectionDto[] {
  const allElements = sections.flatMap(
    (section) => section.formElementSubSections?.flatMap((subsection) => subsection.formElements) ?? []
  )
  const newVisibilityMap = evaluateFormElementVisibility(allElements)

  const clearedSections = clearHiddenFormElementValues(sections, previousVisibilityMap.value, newVisibilityMap)
  previousVisibilityMap.value = newVisibilityMap

  return clearedSections
}

function getSubsectionKey(
  section: FormElementSectionDto | undefined,
  sectionIndex: number,
  subsection: FormElementSubSectionDto
): string {
  if (subsection.id) {
    return subsection.id
  }

  const spawnedFrom = section?.spawnedFromElementReference ?? 'root'
  const templateRef = section?.templateReference ?? 'no_tmpl'
  const title = subsection.title ?? ''

  return `spawned:${spawnedFrom}|tmpl:${templateRef}|sec:${sectionIndex}|title:${title}`
}

function updateSubsectionElements(
  sections: FormElementSectionDto[],
  subsectionKey: string,
  updatedFormElements: FormElementDto[]
): FormElementSectionDto[] {
  return sections.map((section, sectionIdx) => ({
    ...section,
    formElementSubSections: section.formElementSubSections.map((subsection) => {
      if (getSubsectionKey(section, sectionIdx, subsection) === subsectionKey) {
        return { ...subsection, formElements: updatedFormElements }
      }
      return subsection
    })
  }))
}
</script>

<style scoped>
.lch-stepper-scroll {
  -webkit-overflow-scrolling: touch;
}

.lch-stepper-scroll::-webkit-scrollbar {
  height: 0px;
}

.lch-stepper-scroll {
  scrollbar-width: none;
}
</style>
