<script lang="ts" setup>
import type { PublicBookingReceipt, PublicBookingSeatWithUrl } from '~~/shared/booking'

import {
  DINNER_EVENT_DATE_LABEL,
  DINNER_EVENT_TIME_LABEL,
  DINNER_EVENT_TITLE,
  DINNER_EVENT_VENUE,
  formatBookingCurrency,
  getBookingModeLabel,
  getBookingStatusLabel,
  getSeatLabel,
  getTicketCatalogItem
} from '~~/shared/booking'

import { getErrorMessage } from '../../utils/errors'
import { formatDateTime } from '../../utils/formatters'

type ReceiptTabId = 'main' | 'status' | 'seats'

const route = useRoute()
const toast = useToast()
const apiClient = useApiClient()

const token = String(route.params.token || '')
const activeTab = ref<ReceiptTabId>('main')
const receiptActionLoading = ref(false)
const shareSeatsLoading = ref(false)
const seatActionId = ref<string | null>(null)
const expandedSeatIds = ref<string[]>([])
const shareForm = reactive({
  count: 1,
  recipientName: '',
  recipientPhone: ''
})

const tabs = [
  { id: 'main' as const, label: 'Main QR', icon: 'i-lucide-qr-code' },
  { id: 'status' as const, label: 'Status', icon: 'i-lucide-badge-check' },
  { id: 'seats' as const, label: 'Seat List', icon: 'i-lucide-users' }
]

let initialReceipt: PublicBookingReceipt

try {
  initialReceipt = await apiClient<PublicBookingReceipt>(`/api/public/receipts/${token}`)
} catch (error: any) {
  throw createError({
    statusCode: error?.statusCode || error?.data?.statusCode || 404,
    statusMessage: error?.data?.statusMessage || error?.message || 'Receipt not found'
  })
}

const receipt = ref(initialReceipt)

const ticketLabel = computed(() => getTicketCatalogItem(receipt.value.booking.ticketType)?.label || receipt.value.booking.ticketType.toUpperCase())
const totalFormatted = computed(() => formatBookingCurrency(receipt.value.booking.totalPrice))
const statusColor = computed(() => receipt.value.booking.status === 'confirmed' ? 'success' : 'warning')
const sharedSeats = computed(() => receipt.value.seats.filter((seat) => Boolean(seat.sharedAt)))
const availableSeats = computed(() => receipt.value.seats.filter((seat) => !seat.sharedAt))
const maxShareCount = computed(() => Math.max(availableSeats.value.length, 1))
const normalizedShareCount = computed(() => {
  return Math.max(1, Math.min(Math.trunc(Number(shareForm.count) || 1), maxShareCount.value))
})
const seatsToShare = computed(() => availableSeats.value.slice(0, normalizedShareCount.value))
const seatsToShareLabel = computed(() => seatsToShare.value.map((seat) => getSeatLabel(seat.seatNumber)).join(', '))

const detailRows = computed(() => {
  const rows = [
    { label: 'Guest', value: receipt.value.booking.customerName },
    { label: 'Phone', value: receipt.value.booking.customerPhone },
    { label: 'Booking', value: getBookingModeLabel(receipt.value.booking.bookingMode) },
    { label: 'Category', value: ticketLabel.value },
    { label: 'Quantity', value: String(receipt.value.booking.quantity) },
    { label: 'Seats', value: String(receipt.value.booking.seatCount) },
    { label: 'Submitted', value: formatDateTime(receipt.value.booking.createdAt) }
  ]

  if (receipt.value.booking.confirmedAt) {
    rows.push({
      label: 'Confirmed',
      value: formatDateTime(receipt.value.booking.confirmedAt)
    })
  }

  return rows
})

watch(
  availableSeats,
  (nextSeats) => {
    shareForm.count = Math.max(1, Math.min(shareForm.count, Math.max(nextSeats.length, 1)))
  },
  { immediate: true }
)

function updateSeat(nextSeat: PublicBookingSeatWithUrl) {
  receipt.value = {
    ...receipt.value,
    seats: receipt.value.seats.map((seat) => seat.id === nextSeat.id ? nextSeat : seat)
  }
}

function isSeatExpanded(seatId: string) {
  return expandedSeatIds.value.includes(seatId)
}

function toggleSeatExpanded(seatId: string) {
  expandedSeatIds.value = isSeatExpanded(seatId)
    ? expandedSeatIds.value.filter((id) => id !== seatId)
    : [...expandedSeatIds.value, seatId]
}

function buildSeatBundleText(seats: PublicBookingSeatWithUrl[]) {
  const recipientLabel = shareForm.recipientName.trim()
    ? `Recipient: ${shareForm.recipientName.trim()}`
    : null

  return [
    DINNER_EVENT_TITLE,
    `Guest: ${receipt.value.booking.customerName}`,
    recipientLabel,
    `Seats: ${seats.map((seat) => getSeatLabel(seat.seatNumber)).join(', ')}`,
    `Category: ${ticketLabel.value}`,
    `Date: ${DINNER_EVENT_DATE_LABEL}`,
    `Time: ${DINNER_EVENT_TIME_LABEL}`,
    `Venue: ${DINNER_EVENT_VENUE}`,
    '',
    ...seats.flatMap((seat) => [
      `${getSeatLabel(seat.seatNumber)}:`,
      seat.seatUrl,
      ''
    ])
  ].filter(Boolean).join('\n')
}

async function shareLink(options: {
  title: string
  text: string
  url?: string
  clipboardText?: string
  successTitle: string
  successDescription: string
}) {
  if (!import.meta.client) {
    return false
  }

  const clipboardText = options.clipboardText || options.url || options.text

  try {
    if (navigator.share) {
      await navigator.share({
        title: options.title,
        text: options.text,
        url: options.url
      })
    } else if (navigator.clipboard?.writeText) {
      await navigator.clipboard.writeText(clipboardText)

      toast.add({
        title: options.successTitle,
        description: `${options.successDescription} Copied to clipboard.`,
        color: 'success',
        icon: 'i-lucide-copy-check'
      })
    } else {
      window.prompt('Copy this text', clipboardText)
    }

    return true
  } catch (error: any) {
    if (error?.name === 'AbortError') {
      return false
    }

    throw error
  }
}

async function patchSeatShare(
  seat: PublicBookingSeatWithUrl,
  body: {
    shared: boolean
    recipientName?: string
    recipientPhone?: string
  }
) {
  const response = await apiClient<{ seat: PublicBookingSeatWithUrl }>(
    `/api/public/receipts/${token}/seats/${seat.id}`,
    {
      method: 'PATCH',
      body
    }
  )

  updateSeat(response.seat)
  return response.seat
}

async function shareReceiptLink() {
  if (receiptActionLoading.value) {
    return
  }

  receiptActionLoading.value = true

  try {
    const shared = await shareLink({
      title: `${DINNER_EVENT_TITLE} receipt`,
      text: `Ticket receipt for ${receipt.value.booking.customerName}.`,
      url: receipt.value.receiptUrl,
      successTitle: 'Receipt ready',
      successDescription: 'Main receipt link prepared.'
    })

    if (shared && import.meta.client && navigator.share) {
      toast.add({
        title: 'Receipt shared',
        color: 'success',
        icon: 'i-lucide-share-2'
      })
    }
  } catch (error) {
    toast.add({
      title: 'Unable to share receipt',
      description: getErrorMessage(error, 'Please try again in a moment.'),
      color: 'error',
      icon: 'i-lucide-circle-alert'
    })
  } finally {
    receiptActionLoading.value = false
  }
}

async function shareSeats() {
  if (!availableSeats.value.length || shareSeatsLoading.value || seatActionId.value) {
    return
  }

  shareSeatsLoading.value = true

  try {
    const seats = seatsToShare.value
    const shared = await shareLink({
      title: `${DINNER_EVENT_TITLE} seats`,
      text: buildSeatBundleText(seats),
      clipboardText: buildSeatBundleText(seats),
      successTitle: 'Seats ready',
      successDescription: `${seats.length} seat link${seats.length > 1 ? 's are' : ' is'} ready to send.`
    })

    if (!shared) {
      return
    }

    let successCount = 0

    for (const seat of seats) {
      try {
        await patchSeatShare(seat, {
          shared: true,
          recipientName: shareForm.recipientName,
          recipientPhone: shareForm.recipientPhone
        })
        successCount += 1
      } catch {
        continue
      }
    }

    if (!successCount) {
      toast.add({
        title: 'Seat update failed',
        description: 'The share sheet opened, but the seat records could not be updated.',
        color: 'error',
        icon: 'i-lucide-circle-alert'
      })
      return
    }

    toast.add({
      title: `${successCount} seat${successCount > 1 ? 's' : ''} shared`,
      description: successCount === seats.length
        ? 'Next available seats were sent.'
        : 'Some seats were sent, but at least one update failed.',
      color: successCount === seats.length ? 'success' : 'warning',
      icon: successCount === seats.length ? 'i-lucide-check-check' : 'i-lucide-triangle-alert'
    })
  } catch (error) {
    toast.add({
      title: 'Unable to share seats',
      description: getErrorMessage(error, 'Please try again in a moment.'),
      color: 'error',
      icon: 'i-lucide-circle-alert'
    })
  } finally {
    shareSeatsLoading.value = false
  }
}

async function unshareSeat(seat: PublicBookingSeatWithUrl) {
  if (seatActionId.value || shareSeatsLoading.value) {
    return
  }

  if (import.meta.client && !window.confirm(`Unshare ${getSeatLabel(seat.seatNumber)}? The previous link will stop working.`)) {
    return
  }

  seatActionId.value = seat.id

  try {
    await patchSeatShare(seat, { shared: false })

    toast.add({
      title: `${getSeatLabel(seat.seatNumber)} unshared`,
      color: 'success',
      icon: 'i-lucide-rotate-ccw'
    })
  } catch (error) {
    toast.add({
      title: 'Unable to unshare seat',
      description: getErrorMessage(error, 'Please try again in a moment.'),
      color: 'error',
      icon: 'i-lucide-circle-alert'
    })
  } finally {
    seatActionId.value = null
  }
}
</script>

<template>
  <UContainer class="py-6 sm:py-8">
    <div class="mx-auto max-w-5xl space-y-5">
      <div class="space-y-1 text-center">
        <UBadge label="Ticket Receipt" color="primary" variant="soft" class="rounded-full" />
        <h1 class="text-2xl font-bold tracking-tight text-highlighted sm:text-3xl">
          {{ DINNER_EVENT_TITLE }}
        </h1>
      </div>

      <div class="overflow-x-auto rounded-2xl border border-default bg-default p-2 shadow-sm">
        <div class="flex min-w-max gap-2 sm:min-w-0 sm:grid sm:grid-cols-3">
          <button
            v-for="tab in tabs"
            :key="tab.id"
            type="button"
            class="flex min-h-11 min-w-32 items-center justify-center gap-2 rounded-xl px-4 py-3 text-sm font-medium transition sm:min-w-0"
            :class="activeTab === tab.id
              ? 'bg-primary text-inverted shadow-sm'
              : 'bg-elevated text-default hover:bg-muted'"
            @click="activeTab = tab.id"
          >
            <UIcon :name="tab.icon" class="size-4" />
            <span>{{ tab.label }}</span>
          </button>
        </div>
      </div>

      <UCard
        v-if="activeTab === 'main'"
        class="border border-default bg-default shadow-sm"
        :ui="{ body: 'space-y-5 p-4 sm:p-6' }"
      >
        <div class="grid gap-5 lg:grid-cols-[18rem_minmax(0,1fr)]">
          <div class="space-y-4 rounded-2xl border border-default bg-elevated p-4 text-center">
            <QrCodeSvg :value="receipt.receiptUrl" :size="220" />

            <div class="flex flex-col gap-2">
              <UButton
                label="Share Receipt"
                icon="i-lucide-share-2"
                class="justify-center"
                :loading="receiptActionLoading"
                @click="shareReceiptLink"
              />
              <UButton
                :to="receipt.receiptUrl"
                target="_blank"
                label="Open Link"
                color="neutral"
                variant="outline"
                icon="i-lucide-external-link"
                class="justify-center"
              />
            </div>
          </div>

          <div class="grid gap-3 sm:grid-cols-2 xl:grid-cols-4">
            <div class="rounded-2xl border border-default bg-elevated p-4">
              <p class="text-xs uppercase tracking-wide text-muted">
                Status
              </p>
              <div class="mt-2">
                <UBadge :label="getBookingStatusLabel(receipt.booking.status)" :color="statusColor" variant="soft" />
              </div>
            </div>
            <div class="rounded-2xl border border-default bg-elevated p-4">
              <p class="text-xs uppercase tracking-wide text-muted">
                Shared
              </p>
              <p class="mt-2 text-2xl font-bold text-highlighted">
                {{ sharedSeats.length }}
              </p>
            </div>
            <div class="rounded-2xl border border-default bg-elevated p-4">
              <p class="text-xs uppercase tracking-wide text-muted">
                Available
              </p>
              <p class="mt-2 text-2xl font-bold text-highlighted">
                {{ availableSeats.length }}
              </p>
            </div>
            <div class="rounded-2xl border border-default bg-elevated p-4">
              <p class="text-xs uppercase tracking-wide text-muted">
                Total
              </p>
              <p class="mt-2 text-2xl font-bold text-highlighted">
                {{ totalFormatted }}
              </p>
            </div>

            <div class="overflow-hidden rounded-2xl border border-default sm:col-span-2 xl:col-span-4">
              <div
                v-for="row in detailRows"
                :key="row.label"
                class="grid grid-cols-[6.5rem_minmax(0,1fr)] gap-3 border-b border-default px-4 py-3 text-sm last:border-b-0 sm:grid-cols-[9rem_minmax(0,1fr)]"
              >
                <div class="text-xs font-medium uppercase tracking-wide text-muted sm:text-sm sm:normal-case sm:tracking-normal">
                  {{ row.label }}
                </div>
                <div class="min-w-0 font-medium text-highlighted break-words">
                  {{ row.value }}
                </div>
              </div>
            </div>
          </div>
        </div>
      </UCard>

      <UCard
        v-else-if="activeTab === 'status'"
        class="border border-default bg-default shadow-sm"
        :ui="{ body: 'space-y-4 p-4 sm:p-6' }"
      >
        <div class="grid gap-3 sm:grid-cols-2 lg:grid-cols-4">
          <div class="rounded-2xl border border-default bg-elevated p-4">
            <p class="text-xs uppercase tracking-wide text-muted">
              Status
            </p>
            <div class="mt-2">
              <UBadge :label="getBookingStatusLabel(receipt.booking.status)" :color="statusColor" variant="soft" />
            </div>
          </div>
          <div class="rounded-2xl border border-default bg-elevated p-4">
            <p class="text-xs uppercase tracking-wide text-muted">
              Date
            </p>
            <p class="mt-2 font-semibold text-highlighted">
              {{ DINNER_EVENT_DATE_LABEL }}
            </p>
          </div>
          <div class="rounded-2xl border border-default bg-elevated p-4">
            <p class="text-xs uppercase tracking-wide text-muted">
              Time
            </p>
            <p class="mt-2 font-semibold text-highlighted">
              {{ DINNER_EVENT_TIME_LABEL }}
            </p>
          </div>
          <div class="rounded-2xl border border-default bg-elevated p-4">
            <p class="text-xs uppercase tracking-wide text-muted">
              Venue
            </p>
            <p class="mt-2 font-semibold text-highlighted">
              {{ DINNER_EVENT_VENUE }}
            </p>
          </div>
        </div>

        <div class="overflow-hidden rounded-2xl border border-default">
          <div
            v-for="row in detailRows"
            :key="row.label"
            class="grid grid-cols-[6.5rem_minmax(0,1fr)] gap-3 border-b border-default px-4 py-3 text-sm last:border-b-0 sm:grid-cols-[9rem_minmax(0,1fr)]"
          >
            <div class="text-xs font-medium uppercase tracking-wide text-muted sm:text-sm sm:normal-case sm:tracking-normal">
              {{ row.label }}
            </div>
            <div class="min-w-0 font-medium text-highlighted break-words">
              {{ row.value }}
            </div>
          </div>
        </div>
      </UCard>

      <UCard
        v-else
        class="border border-default bg-default shadow-sm"
        :ui="{ body: 'space-y-5 p-4 sm:p-6' }"
      >
        <div class="grid gap-4 xl:grid-cols-[20rem_minmax(0,1fr)]">
          <div class="space-y-4 rounded-2xl border border-default bg-elevated p-4">
            <div class="grid gap-3 sm:grid-cols-2 xl:grid-cols-1">
              <div class="rounded-2xl border border-default bg-default p-4">
                <p class="text-xs uppercase tracking-wide text-muted">
                  Seats To Share
                </p>
                <UInputNumber
                  v-model="shareForm.count"
                  :min="1"
                  :max="maxShareCount"
                  :disabled="!availableSeats.length || shareSeatsLoading"
                  size="xl"
                  class="mt-3 w-full"
                />
              </div>
              <div class="rounded-2xl border border-default bg-default p-4">
                <p class="text-xs uppercase tracking-wide text-muted">
                  Next Seats
                </p>
                <p class="mt-2 text-sm font-medium text-highlighted break-words">
                  {{ availableSeats.length ? seatsToShareLabel : 'No seats available' }}
                </p>
              </div>
            </div>

            <UFormField label="Recipient Name">
              <UInput
                v-model="shareForm.recipientName"
                class="w-full"
                placeholder="Optional"
              />
            </UFormField>

            <UFormField label="Recipient Phone">
              <UInput
                v-model="shareForm.recipientPhone"
                type="tel"
                class="w-full"
                placeholder="Optional"
              />
            </UFormField>

            <UButton
              label="Share Seats"
              icon="i-lucide-share-2"
              class="w-full justify-center"
              :disabled="!availableSeats.length || shareSeatsLoading || Boolean(seatActionId)"
              :loading="shareSeatsLoading"
              @click="shareSeats"
            />
          </div>

          <div class="space-y-3">
            <div
              v-for="seat in receipt.seats"
              :key="seat.id"
              class="overflow-hidden rounded-2xl border border-default bg-elevated"
            >
              <button
                type="button"
                class="flex min-h-11 w-full items-start justify-between gap-3 px-4 py-4 text-left"
                @click="toggleSeatExpanded(seat.id)"
              >
                <div class="space-y-1">
                  <div class="flex flex-wrap items-center gap-2">
                    <p class="text-base font-semibold text-highlighted">
                      {{ getSeatLabel(seat.seatNumber) }}
                    </p>
                    <UBadge
                      :label="seat.sharedAt ? 'Shared' : 'Available'"
                      :color="seat.sharedAt ? 'primary' : 'neutral'"
                      variant="soft"
                      size="sm"
                    />
                  </div>
                  <p class="text-sm text-muted">
                    {{ seat.recipientName || 'Unassigned' }}
                    <span v-if="seat.recipientPhone"> · {{ seat.recipientPhone }}</span>
                  </p>
                </div>

                <UIcon
                  name="i-lucide-chevron-down"
                  class="mt-1 size-4 shrink-0 text-muted transition-transform"
                  :class="isSeatExpanded(seat.id) ? 'rotate-180' : ''"
                />
              </button>

              <div
                v-if="isSeatExpanded(seat.id)"
                class="border-t border-default bg-default px-4 py-4"
              >
                <div class="grid gap-4 lg:grid-cols-[12rem_minmax(0,1fr)]">
                  <div class="flex justify-center">
                    <QrCodeSvg :value="seat.seatUrl" :size="170" />
                  </div>

                  <div class="space-y-3">
                    <div class="rounded-2xl border border-default bg-elevated p-4 text-sm text-default">
                      <p class="font-medium text-highlighted">
                        {{ seat.recipientName || 'Unassigned' }}
                      </p>
                      <p v-if="seat.recipientPhone" class="mt-1 text-muted">
                        {{ seat.recipientPhone }}
                      </p>
                      <p class="mt-2 text-muted">
                        {{ seat.sharedAt ? `Shared ${formatDateTime(seat.sharedAt)}` : 'Available to share' }}
                      </p>
                    </div>

                    <div class="flex flex-col gap-2 sm:flex-row">
                      <UButton
                        :to="seat.seatUrl"
                        target="_blank"
                        label="Open Seat"
                        color="neutral"
                        variant="outline"
                        icon="i-lucide-external-link"
                        class="flex-1 justify-center"
                      />
                      <UButton
                        label="Unshare"
                        color="neutral"
                        variant="outline"
                        icon="i-lucide-user-minus"
                        class="flex-1 justify-center"
                        :disabled="!seat.sharedAt || seatActionId === seat.id || shareSeatsLoading"
                        @click="unshareSeat(seat)"
                      />
                    </div>
                  </div>
                </div>
              </div>
            </div>
          </div>
        </div>
      </UCard>
    </div>
  </UContainer>
</template>
