<script setup lang="ts">
// REFACTOR @Iskander
import ui from './ui.config'
import {Disclosure, DisclosureButton, DisclosurePanel} from '@headlessui/vue'
import {twJoin, twMerge} from 'tailwind-merge'
import type {Color, Size} from "#adata-ui/components/elements/accordion/types";

export interface Props {
  label: string
  content?: any
  defaultOpen?: boolean
  disabled?: boolean
  size?: Size
  color?: Color
  slot?: string
  contentClass?: string
  bodyClass?: string
  activateOpenBg?: boolean
}

interface Emits {
  (e: 'toggle', isOpen: boolean): void

  (e: 'open'): void

  (e: 'close'): void
}

defineOptions({
  inheritAttrs: false
})
const attrs = useAttrs()

const props = withDefaults(defineProps<Props>(), {
  defaultOpen: false,
  disabled: false,
  size: 'md',
  color: 'gray',
  slot: undefined
})


const emit = defineEmits<Emits>()

const buttonClass = computed(() =>
  twMerge(twJoin(ui.item.color[props.color], ui.ring, ui.item.button, ui.item.size[props.size]))
)

function onEnter(_el: Element, done: () => void) {
  const el = _el as HTMLElement
  el.style.height = '0'
  el.offsetHeight // Trigger a reflow, flushing the CSS changes
  el.style.height = el.scrollHeight + 'px'

  el.addEventListener('transitionend', done, {once: true})
}

function onBeforeLeave(_el: Element) {
  const el = _el as HTMLElement
  el.style.height = el.scrollHeight + 'px'
  el.offsetHeight // Trigger a reflow, flushing the CSS changes
}

function onAfterEnter(_el: Element) {
  const el = _el as HTMLElement
  el.style.height = 'auto'
}

function onLeave(_el: Element, done: () => void) {
  const el = _el as HTMLElement
  el.style.height = '0'

  el.addEventListener('transitionend', done, {once: true})
}

const contClass = computed(() => twMerge(twJoin(ui.item.content, props.contentClass)))
const bodyClassCompute = computed(() => twMerge(twJoin(ui.item.accordion, props.activateOpenBg ? isOpen.value && props.bodyClass : props.bodyClass)))

const accordion = ref()

const isOpen = ref()

function updateState() {
  if (accordion.value) {
    const state = accordion.value?.el.getAttribute('data-headlessui-state')
    isOpen.value = !!state
  }
}

onMounted(() => {
  if (accordion.value) {
    updateState()

    const observer = new MutationObserver(() => {
      updateState()
    })

    observer.observe(accordion.value?.el, {
      attributes: true,
      attributeFilter: ['data-headlessui-state']
    })

    onBeforeUnmount(() => {
      observer.disconnect()
    })
  }
})

function emulateButtonClick() {
  if (accordion.value) {
    accordion.value?.el.click()
  }
}

const handelOpen = () => {
  if (!isOpen.value) {
    emulateButtonClick()
  }
}
const handelClose = () => {
  if (isOpen.value) {
    emulateButtonClick()
  }
}

watch(isOpen, () => {
  emit('toggle', isOpen.value)
  isOpen.value ? emit('open') : emit('close')
})

defineExpose({
  ontoggle: emulateButtonClick,
  handelOpen,
  handelClose
})
</script>

<template>
  <Disclosure
    v-slot="{ open, close }"
    as="div"
    :class="bodyClassCompute"
    :default-open="defaultOpen"
    v-bind="{ ...attrs }"
  >
    <DisclosureButton
      ref="accordion"
      :disabled="disabled"
      as="template"
    >
      <slot
        name="head"
        :open="open"
        :close="close"
      >
        <button :class="buttonClass">
          <span :class="size === 'md' ? 'text-sm': 'text-base'">{{ label }}</span>
          <slot name="additional"/>
          <a-icon-chevron-down
            :arrow-attrs="{ class: 'stroke-deepblue-900' }"
            :class="[{ 'rotate-180': open }, 'max-h-[16px] min-h-[16px] min-w-[16px] max-w-[16px]', ui.item.icon]"
          />
        </button>
      </slot>
    </DisclosureButton>
    <slot
      name="closedToShow"
      :open="open"
      :close="close"
    />
    <Transition
      v-bind="ui.transition"
      @enter="onEnter"
      @after-enter="onAfterEnter"
      @before-leave="onBeforeLeave"
      @leave="onLeave"
    >
      <div v-show="open">
        <DisclosurePanel static>
          <div :class="contClass">
            <slot
              :name="slot || 'default'"
              :content="content"
              :open="open"
              :close="close"
            >
              {{ content }}
            </slot>
          </div>
        </DisclosurePanel>
      </div>
    </Transition>
  </Disclosure>
</template>

<style scoped></style>
