<template>
  <Teleport to="body">
    <Transition
      name="drawer"
      appear
      @after-leave="isRendered = false"
    >
      <div
        v-if="isRendered && isOpen"
        :id="componentId"
        class="fixed inset-0 z-50 flex justify-end"
        v-bind="attrs"
      >
        <div
          class="absolute inset-0 bg-black/40"
          data-test="backdrop"
          @click="close"
        />

        <div
          :class="twMerge(
            'relative z-50 flex h-full w-full max-w-md flex-col bg-white shadow-xl',
            drawerClass,
          )"
          role="dialog"
          :aria-modal="true"
          :aria-labelledby="titleId"
          data-test="panel"
        >
          <div class="flex items-center justify-between px-5 pb-8 pt-8">
            <h2
              :id="titleId"
              class="text-[32px] font-semibold text-m-primary"
            >
              {{ title }}
            </h2>
            <button
              v-if="showClose"
              type="button"
              aria-label="Fermer"
              class="flex h-8 w-8 cursor-pointer items-center justify-center rounded-full transition-colors hover:bg-m-surface"
              data-test="close-button"
              @click="close"
            >
              <IconifyIcon
                icon="mdi:close"
                :width="24"
                :height="24"
              />
            </button>
          </div>

          <div
            class="flex-1 overflow-y-auto px-5"
          >
            <slot />
          </div>
        </div>
      </div>
    </Transition>
  </Teleport>
</template>

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

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

const props = withDefaults(
  defineProps<{
    id?: string
    modelValue?: boolean
    title?: string
    showClose?: boolean
    drawerClass?: string
  }>(),
  {
    id: '',
    modelValue: undefined,
    title: '',
    showClose: true,
    drawerClass: '',
  },
)

const emit = defineEmits<{
  (e: 'update:modelValue', value: boolean): void
}>()

const attrs = useAttrs()
const generatedId = useId()

const componentId = computed(() => props.id || `malio-drawer-${generatedId}`)
const titleId = computed(() => `${componentId.value}-title`)

const isControlled = computed(() => props.modelValue !== undefined)
const localValue = ref(false)

const isOpen = computed(() =>
  isControlled.value ? props.modelValue! : localValue.value,
)

const isRendered = ref(isOpen.value)

watch(isOpen, (val) => {
  if (val) isRendered.value = true
})

function close() {
  if (!isControlled.value) {
    localValue.value = false
  }
  emit('update:modelValue', false)
}
</script>

<style scoped>
.drawer-enter-active,
.drawer-leave-active {
  transition: opacity 0.2s ease;
}

.drawer-enter-active > div:last-child,
.drawer-leave-active > div:last-child {
  transition: transform 0.3s ease;
}

.drawer-enter-from,
.drawer-leave-to {
  opacity: 0;
}

.drawer-enter-from > div:last-child,
.drawer-leave-to > div:last-child {
  transform: translateX(100%);
}
</style>
