<template>
  <button
    :id="seatId"
    ref="seatWrapper"
    v-tooltip="dynamicSeatTooltip"
    class="cpSeatMapSeatWrapper"
    :class="seatWrapperDynamicClass"
    :disabled="isSeatDisabled"
    type="button"
    @click="handleSelectSeat"
  >
    <cp-seat-map-seat class="cpSeatMapSeatWrapper__seat" :seat="seatProperties">
      {{ seatValue }}
      <cp-badge
        v-if="hasLinkedTraveler"
        class="cpSeatMapSeatWrapper__additionalTraveler"
        color="accent"
        :leading-icon="linkedTravelerIcon"
        size="xs"
        variant="outline"
      />
    </cp-seat-map-seat>
  </button>
</template>

<script setup lang="ts">
import { vTooltip } from 'floating-vue'
import { computed, useTemplateRef, watch } from 'vue'

import type { CpSeatMapConfig } from '@/constants/seatMap/CpSeatMapConfig'
import type { CpSeatMapSeatSelection } from '@/constants/seatMap/CpSeatMapSeatSelection'
import type { Seat } from '@/constants/seatMap/Seat'

import { DEFAULT_CP_SEAT_MAP_CONFIG } from '@/constants/seatMap/CpSeatMapConfig'
import { SeatStatuses } from '@/constants/seatMap/SeatStatuses'
import { displaySeat, getTravelerIcon } from '@/helpers/seatMap'
import CpBadge from './CpBadge.vue'
import CpSeatMapSeat from './CpSeatMapSeat.vue'

interface Props {
  config?: CpSeatMapConfig
  isHighlighted?: boolean
  isSelectionEnabled?: boolean
  rowNumber: number
  seat: Seat
  selection?: CpSeatMapSeatSelection | null
}

const props = withDefaults(defineProps<Props>(), {
  config: () => DEFAULT_CP_SEAT_MAP_CONFIG,
  isHighlighted: false,
  isSelectionEnabled: true,
  selection: null,
})

const emit = defineEmits<{ select: [seat: Seat, rowNumber: number] }>()

const HIGHLIGHT_DURATION = 500

const seatWrapperRef = useTemplateRef<HTMLButtonElement>('seatWrapper')

const seatId = computed(() => `seat-${displaySeat({ row: props.rowNumber, column: props.seat.column })}`)

const isSeatSelected = computed(() => props.selection !== null)

const isSeatOccupied = computed(() => props.seat.status === SeatStatuses.OCCUPIED)
const isSeatBlocked = computed(() => props.seat.status === SeatStatuses.BLOCKED)
const isSeatUnavailable = computed(() => isSeatBlocked.value || isSeatOccupied.value)
const isSeatPayable = computed(() => props.seat.status === SeatStatuses.PAYABLE)

const highlightSeat = () => {
  if (!seatWrapperRef.value) return

  seatWrapperRef.value.classList.add('cpSeatMapSeatWrapper--isHighlighted')
  seatWrapperRef.value.scrollIntoView({ behavior: 'smooth', block: 'center' })

  setTimeout(() => {
    if (!seatWrapperRef.value) return
    seatWrapperRef.value.classList.remove('cpSeatMapSeatWrapper--isHighlighted')
  }, HIGHLIGHT_DURATION)
}

watch(
  () => props.isHighlighted,
  (isHighlighted) => {
    if (isHighlighted) highlightSeat()
  },
)

const seatWrapperDynamicClass = computed(() => {
  return {
    'cpSeatMapSeatWrapper--isPayable': isSeatPayable.value,
  }
})

const isSeatDisabled = computed(() => {
  if (!props.isSelectionEnabled) return true
  return isSeatUnavailable.value
})

const dynamicSeatStatus = computed(() => {
  if (!isSeatSelected.value) {
    if (isSeatUnavailable.value || isSeatPayable.value) return props.seat.status
    return SeatStatuses.FREE
  }

  return SeatStatuses.OCCUPIED_BY_CURRENT_PAX
})

const seatProperties = computed(() => ({
  ...props.seat,
  status: dynamicSeatStatus.value,
}))

const hasLinkedTraveler = computed(() => !!props.selection?.hasLinkedTraveler)

const linkedTravelerIcon = computed(() => {
  if (!hasLinkedTraveler.value) return ''
  return getTravelerIcon(props.selection?.linkedTravelerType) || 'infant'
})

const dynamicSeatTooltip = computed(() => {
  const { seatStatuses } = props.config

  if (isSeatSelected.value) {
    if (hasLinkedTraveler.value) return seatStatuses.selectedForLinkedTraveler

    return seatStatuses.selected
  }

  if (!props.isSelectionEnabled) return seatStatuses.selectTravelerFirst

  const seatLabel = displaySeat({ row: props.rowNumber, column: props.seat.column })

  return `${seatLabel} • ${seatStatuses[props.seat.status]}`
})

const seatValue = computed(() => props.selection?.initials || '')

const handleSelectSeat = () => {
  if (isSeatDisabled.value) return
  emit('select', props.seat, props.rowNumber)
}
</script>

<style lang="scss">
.cpSeatMapSeatWrapper {
  position: relative;
  display: flex;
  align-items: center;
  justify-content: center;
  transition: transform 200ms ease;

  &:focus-visible {
    @extend %u-focus-outline;

    border-radius: var(--cp-radius-sm);
    outline-offset: fn.px-to-rem(1);
  }

  &--isPayable:focus-visible {
    outline-color: var(--cp-border-warning-primary);
  }

  &:disabled {
    cursor: not-allowed;
  }

  &--isHighlighted {
    transform: scale(1.15);

    > * {
      outline: fn.px-to-rem(1) solid var(--cp-background-accent-solid-hover);
      outline-offset: fn.px-to-rem(1);
    }
  }

  &__additionalTraveler {
    position: absolute;

    // stylelint-disable-next-line custom-property-pattern
    top: calc(var(--cp-dimensions-1_5) * -1);

    // stylelint-disable-next-line custom-property-pattern
    right: calc(var(--cp-dimensions-1_5) * -1);
    padding: var(--cp-spacing-xs);

    .cpBadge__icon {
      width: fn.px-to-rem(12);
    }
  }
}
</style>
