<template>
  <div>
    <h3 class="m-0">
      <button
        :id="headerId"
        ref="headerRef"
        type="button"
        :class="headerClasses"
        :aria-expanded="open"
        :aria-controls="panelId"
        :disabled="disabled"
        :aria-disabled="disabled || undefined"
        @click="onToggle"
        @keydown.down.prevent="ctx.focusSibling(value, 1)"
        @keydown.up.prevent="ctx.focusSibling(value, -1)"
      >
        <span>{{ title }}</span>
        <IconifyIcon
          icon="mdi:chevron-down"
          :width="24"
          class="shrink-0 transition-transform duration-200"
          :class="open ? 'rotate-180' : ''"
        />
      </button>
    </h3>
    <div
      :id="panelId"
      role="region"
      :aria-labelledby="headerId"
      class="grid transition-[grid-template-rows] duration-200 ease-out"
      :class="open ? 'grid-rows-[1fr]' : 'grid-rows-[0fr]'"
      @transitionend="onPanelTransitionEnd"
    >
      <div
        :class="overflowVisible ? 'overflow-visible' : 'overflow-hidden'"
        :inert="!open || undefined"
      >
        <div :class="panelInnerClass">
          <slot />
        </div>
      </div>
    </div>
  </div>
</template>

<script setup lang="ts">
import {computed, inject, onBeforeUnmount, onMounted, ref, useId, watch} from 'vue'
import {Icon as IconifyIcon} from '@iconify/vue'
import {twMerge} from 'tailwind-merge'
import {accordionContextKey} from './context'

defineOptions({name: 'MalioAccordionItem', inheritAttrs: false})

const props = withDefaults(defineProps<{
  title: string
  value?: string
  defaultOpen?: boolean
  disabled?: boolean
  headerClass?: string
  panelClass?: string
}>(), {
  value: '',
  defaultOpen: false,
  disabled: false,
  headerClass: '',
  panelClass: '',
})

const ctx = inject(accordionContextKey)
if (!ctx) {
  throw new Error('MalioAccordionItem doit être utilisé à l\'intérieur de MalioAccordion')
}

const generatedId = useId()
const value = computed(() => props.value || `malio-accordion-item-${generatedId}`)
const headerRef = ref<HTMLButtonElement | null>(null)
const headerId = computed(() => `${ctx.baseId.value}-header-${value.value}`)
const panelId = computed(() => `${ctx.baseId.value}-panel-${value.value}`)
const open = computed(() => ctx.isOpen(value.value))

// Le panneau garde `overflow-hidden` pendant l'animation (clipping requis par
// la transition grid-template-rows), puis passe en `overflow-visible` une fois
// complètement ouvert pour qu'un popover enfant (datepicker, select…) ne soit
// pas rogné. On re-clippe dès le début de la fermeture.
const overflowVisible = ref(false)

watch(open, (isOpen) => {
  if (!isOpen) overflowVisible.value = false
})

function onPanelTransitionEnd(e: TransitionEvent) {
  if (e.propertyName === 'grid-template-rows' && open.value) {
    overflowVisible.value = true
  }
}

function onToggle() {
  if (props.disabled) return
  ctx.toggle(value.value)
}

const headerClasses = computed(() =>
  twMerge(
    'flex w-full items-center justify-between gap-4 px-7 pt-[28px] pb-[20px] text-left font-[600] text-[20px] transition-colors',
    props.disabled ? 'cursor-not-allowed text-m-muted' : 'cursor-pointer hover:bg-m-surface',
    props.headerClass,
  ),
)

const panelInnerClass = computed(() => twMerge('px-7 pt-[10px] pb-[20px]', props.panelClass))

onMounted(() => {
  ctx.register(
    {
      value: value.value,
      getHeaderEl: () => headerRef.value,
      isDisabled: () => props.disabled,
    },
    props.defaultOpen,
  )
  // Ouvert au montage (defaultOpen / contrôlé) : pas d'animation, overflow visible direct.
  if (open.value) overflowVisible.value = true
})

onBeforeUnmount(() => ctx.unregister(value.value))
</script>
