<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,
  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 shareSeatsLoading = ref(false)
const seatActionId = ref<string | null>(null)
const batchShareModalOpen = ref(false)
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 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 statusRows = computed(() => {
  return [
    {
      label: 'Status',
      value: getBookingStatusLabel(receipt.value.booking.status),
      isBadge: true
    },
    {
      label: 'Guest',
      value: receipt.value.booking.customerName
    },
    {
      label: 'Phone Number',
      value: receipt.value.booking.customerPhone
    },
    {
      label: 'Category',
      value: ticketLabel.value
    },
    {
      label: 'Seats',
      value: `${receipt.value.booking.seatCount} seat${receipt.value.booking.seatCount === 1 ? '' : 's'}`
    }
  ]
})

const seatColumns = [
  { accessorKey: 'seatNumber', header: 'Seat Detail' },
  { id: 'open', header: 'Open Link' },
  { id: 'share', header: 'Share' }
]

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 buildSeatBundleText(
  seats: PublicBookingSeatWithUrl[],
  options?: {
    recipientName?: string
    recipientPhone?: string
  }
) {
  const recipientName = options?.recipientName?.trim() || ''
  const recipientPhone = options?.recipientPhone?.trim() || ''
  const recipientLabel = recipientName
    ? `Recipient: ${recipientName}`
    : null
  const recipientPhoneLabel = recipientPhone
    ? `Recipient Phone: ${recipientPhone}`
    : null

  return [
    DINNER_EVENT_TITLE,
    `Guest: ${receipt.value.booking.customerName}`,
    recipientLabel,
    recipientPhoneLabel,
    `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 shareSeats() {
  if (!availableSeats.value.length || shareSeatsLoading.value || seatActionId.value) {
    return false
  }

  shareSeatsLoading.value = true

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

    if (!shared) {
      return false
    }

    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 false
    }

    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'
    })
    return true
  } 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'
    })
    return false
  } finally {
    shareSeatsLoading.value = false
  }
}

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

  seatActionId.value = seat.id

  try {
    const shared = await shareLink({
      title: `${DINNER_EVENT_TITLE} ${getSeatLabel(seat.seatNumber)}`,
      text: buildSeatBundleText([seat]),
      clipboardText: buildSeatBundleText([seat]),
      successTitle: 'Seat ready',
      successDescription: `${getSeatLabel(seat.seatNumber)} is ready to send.`
    })

    if (!shared) {
      return
    }

    await patchSeatShare(seat, { shared: true })

    toast.add({
      title: `${getSeatLabel(seat.seatNumber)} shared`,
      color: 'success',
      icon: 'i-lucide-share-2'
    })
  } catch (error) {
    toast.add({
      title: 'Unable to share seat',
      description: getErrorMessage(error, 'Please try again in a moment.'),
      color: 'error',
      icon: 'i-lucide-circle-alert'
    })
  } finally {
    seatActionId.value = null
  }
}

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
  }
}

async function openBatchShare() {
  const shared = await shareSeats()

  if (shared) {
    batchShareModalOpen.value = false
  }
}
</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="rounded-2xl border border-default bg-default p-1.5 shadow-sm">
        <div class="flex gap-1.5">
          <button
            v-for="tab in tabs"
            :key="tab.id"
            type="button"
            class="flex min-h-10 flex-1 items-center justify-center gap-1.5 rounded-xl px-3 py-2 text-xs font-medium transition sm:text-sm"
            :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: 'p-5 sm:p-8' }"
      >
        <div class="mx-auto flex max-w-sm flex-col items-center gap-5 text-center">
          <div class="rounded-[1.75rem] border border-default bg-elevated p-5 shadow-sm">
            <QrCodeSvg :value="receipt.receiptUrl" :size="240" />
          </div>

          <div class="grid w-full gap-2 sm:grid-cols-3">
            <div class="rounded-2xl border border-default bg-elevated px-4 py-3 text-left">
              <p class="text-[11px] font-medium uppercase tracking-wide text-muted">
                Category
              </p>
              <p class="mt-1 text-sm font-semibold text-highlighted">
                {{ ticketLabel }}
              </p>
            </div>

            <div class="rounded-2xl border border-default bg-elevated px-4 py-3 text-left">
              <p class="text-[11px] font-medium uppercase tracking-wide text-muted">
                Seats
              </p>
              <p class="mt-1 text-sm font-semibold text-highlighted">
                {{ receipt.booking.seatCount }}
              </p>
            </div>

            <div class="rounded-2xl border border-default bg-elevated px-4 py-3 text-left">
              <p class="text-[11px] font-medium uppercase tracking-wide text-muted">
                Price
              </p>
              <p class="mt-1 text-sm font-semibold text-highlighted">
                {{ formatBookingCurrency(receipt.booking.totalPrice) }}
              </p>
            </div>
          </div>

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

      <UCard
        v-else-if="activeTab === 'status'"
        class="border border-default bg-default shadow-sm"
        :ui="{ body: 'p-0' }"
      >
        <div class="overflow-hidden rounded-2xl">
          <div
            v-for="row in statusRows"
            :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 v-if="row.isBadge" class="min-w-0">
              <UBadge :label="row.value" :color="statusColor" variant="soft" />
            </div>
            <div v-else 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="{ header: 'px-4 py-3', body: 'p-0' }"
      >
        <template #header>
          <div class="flex flex-col gap-2 sm:flex-row sm:items-center sm:justify-between">
            <div class="flex flex-wrap gap-2">
              <UBadge :label="`${receipt.seats.length} seats`" color="neutral" variant="soft" />
              <UBadge :label="`${sharedSeats.length} shared`" color="primary" variant="soft" />
              <UBadge :label="`${availableSeats.length} available`" color="neutral" variant="soft" />
            </div>

            <UButton
              label="Batch Share"
              icon="i-lucide-share-2"
              size="sm"
              class="justify-center"
              :disabled="!availableSeats.length || shareSeatsLoading || Boolean(seatActionId)"
              @click="batchShareModalOpen = true"
            />
          </div>
        </template>

        <div class="overflow-x-auto">
          <UTable
            :data="receipt.seats"
            :columns="seatColumns"
            caption="Seats"
            class="min-w-[560px] sm:min-w-[720px]"
          >
            <template #seatNumber-cell="{ row }">
              <div class="min-w-0 space-y-0.5 py-0.5">
                <div class="flex flex-wrap items-center gap-2">
                  <p class="text-sm font-semibold leading-tight text-highlighted sm:text-base">
                    {{ getSeatLabel(row.original.seatNumber) }}
                  </p>
                  <UBadge
                    :label="row.original.sharedAt ? 'Shared' : 'Available'"
                    :color="row.original.sharedAt ? 'primary' : 'neutral'"
                    variant="soft"
                    size="sm"
                  />
                </div>
                <div class="text-xs text-muted">
                  {{ row.original.recipientName || 'Unassigned' }}
                  <span v-if="row.original.recipientPhone"> · {{ row.original.recipientPhone }}</span>
                </div>
                <div class="text-xs text-muted">
                  {{ row.original.sharedAt ? `Shared ${formatDateTime(row.original.sharedAt)}` : 'Ready to share' }}
                </div>
              </div>
            </template>

            <template #open-cell="{ row }">
              <div class="py-0.5">
                <UButton
                  :to="row.original.seatUrl"
                  target="_blank"
                  color="neutral"
                  variant="outline"
                  icon="i-lucide-external-link"
                  size="sm"
                  aria-label="Open seat link"
                  class="min-w-10 justify-center px-2 sm:hidden"
                />
                <UButton
                  :to="row.original.seatUrl"
                  target="_blank"
                  label="Open"
                  color="neutral"
                  variant="outline"
                  icon="i-lucide-external-link"
                  size="sm"
                  class="hidden justify-center sm:inline-flex"
                />
              </div>
            </template>

            <template #share-cell="{ row }">
              <div class="py-0.5">
                <UButton
                  :icon="row.original.sharedAt ? 'i-lucide-user-minus' : 'i-lucide-share-2'"
                  color="neutral"
                  :variant="row.original.sharedAt ? 'outline' : 'solid'"
                  size="sm"
                  :aria-label="row.original.sharedAt ? 'Unshare seat' : 'Share seat'"
                  class="min-w-10 justify-center px-2 sm:hidden"
                  :loading="seatActionId === row.original.id"
                  :disabled="shareSeatsLoading"
                  @click="row.original.sharedAt ? unshareSeat(row.original) : shareSeat(row.original)"
                />
                <UButton
                  :label="row.original.sharedAt ? 'Unshare' : 'Share'"
                  :icon="row.original.sharedAt ? 'i-lucide-user-minus' : 'i-lucide-share-2'"
                  color="neutral"
                  :variant="row.original.sharedAt ? 'outline' : 'solid'"
                  size="sm"
                  class="hidden justify-center sm:inline-flex"
                  :loading="seatActionId === row.original.id"
                  :disabled="shareSeatsLoading"
                  @click="row.original.sharedAt ? unshareSeat(row.original) : shareSeat(row.original)"
                />
              </div>
            </template>
          </UTable>
        </div>
      </UCard>

      <UModal
        v-model:open="batchShareModalOpen"
        title="Batch Share Seats"
        :dismissible="!shareSeatsLoading"
        :close="!shareSeatsLoading"
        :content="{ class: 'sm:max-w-lg' }"
      >
        <template #body>
          <div class="space-y-4">
            <div class="grid gap-3 sm:grid-cols-2">
              <div class="rounded-2xl border border-default bg-elevated 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="lg"
                  class="mt-3 w-full"
                />
              </div>

              <div class="rounded-2xl border border-default bg-elevated 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>

            <div class="flex flex-col-reverse gap-2 sm:flex-row sm:justify-end">
              <UButton
                label="Cancel"
                color="neutral"
                variant="ghost"
                class="justify-center"
                :disabled="shareSeatsLoading"
                @click="batchShareModalOpen = false"
              />

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