<template>
  <div class="cpAccordion">
    <div class="cpAccordion__header" :class="dynamicClasses" cp-item-actions-trigger>
      <button
        :id="accordionId"
        :aria-controls="accordionContentId"
        :aria-expanded="isToggled"
        :aria-labelledby="accordionTitleId"
        class="cpAccordion__trigger"
        type="button"
        @click="handleClick"
      />

      <div v-if="hasActions" class="cpAccordion__actions" :class="actionsDynamicClasses">
        <cp-item-actions :actions="resolvedActions" :quick-options-limit="resolvedQuickOptionsLimit" />
      </div>

      <div class="cpAccordion__title">
        <cp-icon v-if="displayLeadingIcon" class="cpAccordion__icon" size="16" :type="dynamicIcon" />
        <div class="cpAccordion__leading">
          <span :id="accordionTitleId" class="cpAccordion__titleText">{{ title }}</span>
          <slot name="leading-slot" />
        </div>
      </div>

      <span v-if="hasTrailingSlot" class="cpAccordion__trailingSlot">
        <slot name="trailing-slot" />
      </span>

      <div v-if="displayTrailingIcons" class="cpAccordion__trailingIcons">
        <cp-icon v-if="displayActionTrigger" class="cpAccordion__more" size="16" type="more-horizontal" />
        <cp-icon v-if="displayTrailingIcon" class="cpAccordion__icon" size="16" :type="dynamicIcon" />
      </div>
    </div>
    <cp-transition-expand>
      <div v-if="isToggled" :id="accordionContentId" :aria-labelledby="accordionId" class="cpAccordion__content">
        <slot />
      </div>
    </cp-transition-expand>
  </div>
</template>

<script setup lang="ts">
import type { MenuItem } from 'primevue/menuitem'
import { computed, ref, useId, useSlots } from 'vue'

export interface CpAccordionBaseProps {
  defaultOpenState?: boolean
  quickOptionsLimit?: number
  title: string
}

/**
 * Leading (default): optional `actions` (`MenuItem[]`).
 * Trailing: `actions` must not be passed (use `iconPosition: 'trailing'` only).
 */
export type CpAccordionProps =
  | (CpAccordionBaseProps & {
      actions?: MenuItem[]
      hideActionTrigger?: boolean
      iconPosition?: 'leading'
    })
  | (CpAccordionBaseProps & {
      iconPosition: 'trailing'
    })

const props = defineProps<CpAccordionProps>()

const slots = useSlots()

const isToggled = ref(props.defaultOpenState)

const accordionId = useId()

const accordionContentId = computed(() => `${accordionId}-content`)

const accordionTitleId = computed(() => `${accordionId}-title`)

const resolvedIconPosition = computed(() => props.iconPosition || 'leading')

const resolvedQuickOptionsLimit = computed(() => props.quickOptionsLimit || 0)

const resolvedActions = computed<MenuItem[]>(() => {
  if (props.iconPosition === 'trailing') return []
  return props.actions || []
})

const resolvedHideActionTrigger = computed(() => {
  if (props.iconPosition === 'trailing') return true
  return props.hideActionTrigger
})

const hasActions = computed(() => resolvedActions.value.length > 0)
const hasLeadingIcon = computed(() => resolvedIconPosition.value === 'leading')
const hasTrailingIcon = computed(() => resolvedIconPosition.value === 'trailing')
const hasTrailingSlot = computed(() => !!slots['trailing-slot'])

const displayActionTrigger = computed(() => !resolvedHideActionTrigger.value && hasActions.value)
const displayLeadingIcon = computed(() => hasLeadingIcon.value || hasActions.value)
const displayTrailingIcon = computed(() => hasTrailingIcon.value && !hasActions.value)

const displayTrailingIcons = computed(() => displayActionTrigger.value || displayTrailingIcon.value)

const dynamicIcon = computed(() => (isToggled.value ? 'chevron-up' : 'chevron-down'))

const dynamicClasses = computed(() => [{ 'cpAccordion--isOpen': isToggled.value }])

const actionsDynamicClasses = computed(() => ({ 'cpAccordion__actions--hasTrailingSlot': hasTrailingSlot.value }))

const handleClick = () => (isToggled.value = !isToggled.value)
</script>

<style lang="scss">
.cpAccordion {
  display: flex;
  width: 100%;
  flex-direction: column;
  background-color: var(--cp-background-primary);

  &__header {
    position: relative;
    display: flex;
    flex-wrap: nowrap;
    align-items: center;
    padding: var(--cp-spacing-lg);
    border-radius: var(--cp-radius-none);
    gap: var(--cp-spacing-lg);

    &:hover,
    &:has(.cpAccordion__trigger:focus-visible) {
      background-color: var(--cp-background-primary-hover);
    }

    &:has(.cpAccordion__trigger:focus-visible) {
      z-index: 1;
      border-radius: var(--cp-radius-md);
      box-shadow: var(--cp-shadow-focus-ring-accent);
    }
  }

  &__trigger {
    position: absolute;
    width: 100%;
    height: 100%;
    padding: 0;
    border: 0;
    margin: 0;
    background: transparent;
    cursor: pointer;
    inset: 0;
    outline: none;
  }

  &__title {
    display: flex;
    overflow: hidden;
    min-width: 0;
    flex: 1 1 0%;
    align-items: center;
    order: 1;
    font-size: var(--cp-text-size-sm);
    font-weight: 500;
    gap: var(--cp-spacing-lg);
    line-height: var(--cp-line-height-sm);
  }

  &__icon {
    flex-shrink: 0;
    padding: var(--cp-spacing-xs);
    color: var(--cp-foreground-secondary);
    pointer-events: none;
  }

  &__leading {
    display: flex;
    overflow: hidden;
    min-width: 0;
    flex: 1;
    flex-direction: column;
    text-align: left;
  }

  &__titleText {
    @extend %u-text-ellipsis;

    display: block;
    min-width: 0;
  }

  &__trailingSlot {
    display: flex;
    flex-shrink: 0;
    align-items: center;
    order: 2;
    pointer-events: auto;
  }

  &__trailingIcons {
    display: flex;
    flex-shrink: 0;
    align-items: center;
    order: 3;
    gap: var(--cp-spacing-lg);
    pointer-events: none;
  }

  &__actions {
    position: absolute;
    z-index: 1;
    top: 0;
    right: 0;
    display: flex;
    height: 100%;
    align-items: center;
    padding: 0 var(--cp-spacing-md) 0 15%;
    pointer-events: none;

    & > .cpItemActions {
      transform: translate3d(calc(var(--cp-dimensions-1) * 1.25 + #{fn.px-to-rem(-8)}), -50%, 0);
    }
  }

  &__more {
    color: var(--cp-foreground-primary);
    pointer-events: none;
  }
}

@media (hover: hover) and (pointer: fine) {
  [cp-item-actions-trigger]:has(.cpItemActions--isDropdownOpen),
  [cp-item-actions-trigger]:is(:focus-within, :focus-visible, :hover) {
    .cpItemActions {
      transform: translate3d(#{fn.px-to-rem(-8)}, -50%, 0);
    }

    .cpAccordion__actions {
      background: linear-gradient(270deg, var(--cp-utility-neutral-100) 0%, rgba(242, 246, 250, 0%) 100%);
    }
  }
}

// var(--cp-breakpoint-sm) = 40rem = 400px
@include mx.media-query-max(40rem) {
  .cpAccordion {
    &__header {
      flex-wrap: wrap;
    }

    &__trailingIcons {
      order: 2;
    }

    &__trailingSlot {
      flex-basis: 100%;
      order: 3;
      padding-left: var(--cp-spacing-3xl);
    }

    &__actions {
      padding: fn.px-to-rem(7) var(--cp-spacing-md) fn.px-to-rem(7) 15%;
    }

    &__actions--hasTrailingSlot {
      align-items: flex-start;
    }
  }
}
</style>
