<template>
  <main class="detail">
    <!-- Hero image with overlaid header -->
    <div class="detail__hero">
      <img
        class="detail__hero-img"
        src="@/assets/images/event-hero-placeholder.jpg"
        alt=""
      />
      <div class="detail__hero-overlay" />
    </div>

    <!-- Kebab menu (teleported into app header) -->
    <Teleport to="#header-actions">
      <div v-if="state === 'loaded' && event && isOrganizer && !event.cancelled" class="detail__kebab-wrapper">
        <button
          class="detail__kebab-btn"
          type="button"
          aria-label="Event actions"
          :aria-expanded="kebabOpen"
          @click="kebabOpen = !kebabOpen"
        >
          <svg width="20" height="20" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><circle cx="12" cy="5" r="2"/><circle cx="12" cy="12" r="2"/><circle cx="12" cy="19" r="2"/></svg>
        </button>
        <Transition name="kebab-menu">
          <div v-if="kebabOpen" class="detail__kebab-menu" role="menu">
            <button
              class="detail__kebab-item detail__kebab-item--danger"
              type="button"
              role="menuitem"
              @click="kebabOpen = false; cancelSheetOpen = true"
            >
              Cancel event
            </button>
          </div>
        </Transition>
      </div>
    </Teleport>

    <div class="detail__body">
      <!-- Loading state -->
      <div v-if="state === 'loading'" class="detail__content" aria-busy="true" aria-label="Loading event details">
        <div class="skeleton skeleton--title" />
        <div class="skeleton skeleton--line" />
        <div class="skeleton skeleton--line skeleton--short" />
        <div class="skeleton skeleton--line" />
      </div>

      <!-- Loaded state -->
      <div v-else-if="state === 'loaded' && event" class="detail__content">
        <!-- Cancellation banner -->
        <div v-if="event.cancelled" class="detail__cancelled-banner" role="alert">
          <p class="detail__cancelled-banner-title">This event has been cancelled</p>
          <p v-if="event.cancellationReason" class="detail__cancelled-banner-reason">{{ event.cancellationReason }}</p>
        </div>

        <h1 class="detail__title">{{ event.title }}</h1>

        <dl class="detail__meta">
          <div class="detail__meta-item">
            <dt class="detail__meta-icon" aria-label="Date and time">
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
            </dt>
            <dd class="detail__meta-text">{{ formattedDateTime }}</dd>
          </div>

          <div v-if="event.location" class="detail__meta-item">
            <dt class="detail__meta-icon" aria-label="Location">
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M21 10c0 7-9 13-9 13s-9-6-9-13a9 9 0 0 1 18 0z"/><circle cx="12" cy="10" r="3"/></svg>
            </dt>
            <dd class="detail__meta-text">{{ event.location }}</dd>
          </div>

          <div class="detail__meta-item">
            <dt class="detail__meta-icon" aria-label="Attendees">
              <svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M17 21v-2a4 4 0 0 0-4-4H5a4 4 0 0 0-4 4v2"/><circle cx="9" cy="7" r="4"/><path d="M23 21v-2a4 4 0 0 0-3-3.87"/><path d="M16 3.13a4 4 0 0 1 0 7.75"/></svg>
            </dt>
            <dd class="detail__meta-text">{{ event.attendeeCount }} going</dd>
          </div>
        </dl>

        <AttendeeList v-if="isOrganizer && attendeeNames !== null" :attendees="attendeeNames" />

        <div v-if="event.description" class="detail__section">
          <h2 class="detail__section-title">About</h2>
          <p class="detail__description">{{ event.description }}</p>
        </div>
      </div>

      <!-- Not found state -->
      <div v-else-if="state === 'not-found'" class="detail__content detail__content--center" role="status">
        <p class="detail__message">Event not found.</p>
      </div>

      <!-- Error state -->
      <div v-else-if="state === 'error'" class="detail__content detail__content--center" role="alert">
        <p class="detail__message">Something went wrong.</p>
        <button class="btn-primary glass" type="button" @click="fetchEvent">Retry</button>
      </div>
    </div>

    <!-- Organizer bottom bar (not cancelled) -->
    <div v-if="state === 'loaded' && event && isOrganizer && !event.cancelled" class="detail__organizer-bar">
      <div class="detail__organizer-bar-inner">
        <div class="bar-cta glow-border glow-border--animated">
          <button class="bar-cta-btn glass-inner" type="button">
            Post an update
          </button>
        </div>
        <div class="bar-icon glow-border glow-border--animated">
          <button
            class="bar-icon-btn glass-inner"
            type="button"
            aria-label="Add to calendar"
            @click="handleCalendarDownload"
          >
            <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><rect x="3" y="4" width="18" height="18" rx="2"/><line x1="16" y1="2" x2="16" y2="6"/><line x1="8" y1="2" x2="8" y2="6"/><line x1="3" y1="10" x2="21" y2="10"/></svg>
          </button>
        </div>
      </div>
    </div>

    <!-- Cancel event bottom sheet -->
    <BottomSheet :open="cancelSheetOpen" label="Cancel event" @close="cancelSheetOpen = false">
      <h2 class="sheet-title">Cancel event</h2>
      <form class="cancel-form" @submit.prevent="handleCancelEvent" novalidate>
        <div class="form-group">
          <label class="cancel-form__label" for="cancel-reason">Reason (optional)</label>
          <textarea
            id="cancel-reason"
            v-model.trim="cancelReasonInput"
            class="form-field glass cancel-form__textarea"
            placeholder="e.g. Venue no longer available"
            maxlength="2000"
            rows="3"
            @input="cancelEventError = ''"
          />
          <span class="cancel-form__counter">{{ cancelReasonInput.length }} / 2000</span>
        </div>
        <button
          class="cancel-form__confirm glass-inner"
          type="submit"
          :disabled="cancellingEvent"
        >
          {{ cancellingEvent ? 'Cancelling…' : 'Confirm cancellation' }}
        </button>
        <p v-if="cancelEventError" class="cancel-form__error" role="alert">{{ cancelEventError }}</p>
      </form>
    </BottomSheet>

    <!-- Cancel RSVP error message -->
    <div v-if="cancelError" class="detail__cancel-error" role="alert">
      <p>{{ cancelError }}</p>
    </div>

    <!-- RSVP bar (hidden when cancelled) -->
    <RsvpBar
      v-if="state === 'loaded' && event && !isOrganizer && !event.cancelled"
      :has-rsvp="!!rsvpName"
      :bookmarked="eventIsStored"
      @open="sheetOpen = true"
      @cancel="confirmCancelOpen = true"
      @bookmark="handleBookmarkClick"
      @calendar="handleCalendarDownload"
    />

    <!-- Cancel confirmation dialog -->
    <ConfirmDialog
      :open="confirmCancelOpen"
      title="Cancel RSVP?"
      message="The organizer will no longer see you as attending."
      confirm-label="Cancel RSVP"
      cancel-label="Keep"
      @confirm="handleCancelRsvp"
      @cancel="confirmCancelOpen = false"
    />

    <!-- RSVP bottom sheet -->
    <BottomSheet :open="sheetOpen" label="RSVP" @close="sheetOpen = false">
      <h2 class="sheet-title">RSVP</h2>
      <form class="rsvp-form" @submit.prevent="submitRsvp" novalidate>
        <div class="form-group">
          <label class="rsvp-form__label" for="rsvp-name">Your name</label>
          <input
            id="rsvp-name"
            v-model.trim="nameInput"
            class="form-field glass"
            type="text"
            placeholder="e.g. Max Mustermann"
            maxlength="100"
            required
            @input="nameError = ''"
          />
          <span v-if="nameError" class="rsvp-form__field-error" role="alert">{{ nameError }}</span>
        </div>
        <div class="rsvp-form__submit glow-border glow-border--animated">
          <button class="rsvp-form__submit-inner glass-inner" type="submit" :disabled="submitting">
            {{ submitting ? 'Sending…' : "Count me in" }}
          </button>
        </div>
        <p v-if="submitError" class="rsvp-form__field-error rsvp-form__error" role="alert">{{ submitError }}</p>
      </form>
    </BottomSheet>
  </main>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted } from 'vue'
import { useRoute } from 'vue-router'
import { api } from '@/api/client'
import { useEventStorage } from '@/composables/useEventStorage'
import { useIcalDownload } from '@/composables/useIcalDownload'
import AttendeeList from '@/components/AttendeeList.vue'
import BottomSheet from '@/components/BottomSheet.vue'
import ConfirmDialog from '@/components/ConfirmDialog.vue'
import RsvpBar from '@/components/RsvpBar.vue'
import type { components } from '@/api/schema'

type GetEventResponse = components['schemas']['GetEventResponse']
type State = 'loading' | 'loaded' | 'not-found' | 'error'

const route = useRoute()
const { saveRsvp, getRsvp, removeRsvp, getOrganizerToken, saveWatch, isStored, removeEvent } = useEventStorage()
const { download: downloadIcal } = useIcalDownload()

const state = ref<State>('loading')
const event = ref<GetEventResponse | null>(null)

// RSVP state
const sheetOpen = ref(false)
const nameInput = ref('')
const nameError = ref('')
const submitError = ref('')
const submitting = ref(false)
const rsvpName = ref<string | undefined>(undefined)
const confirmCancelOpen = ref(false)
const cancelError = ref('')
const isOrganizer = ref(false)
const attendeeNames = ref<string[] | null>(null)

// Kebab menu state
const kebabOpen = ref(false)

function onKebabClickOutside(e: MouseEvent) {
  const target = e.target as HTMLElement
  if (!target.closest('.detail__kebab-wrapper')) {
    kebabOpen.value = false
  }
}

watch(kebabOpen, (isOpen) => {
  if (isOpen) {
    document.addEventListener('click', onKebabClickOutside, { capture: true })
  } else {
    document.removeEventListener('click', onKebabClickOutside, { capture: true })
  }
})

// Cancel event state
const cancelSheetOpen = ref(false)
const cancelReasonInput = ref('')
const cancelEventError = ref('')
const cancellingEvent = ref(false)

const eventToken = computed(() => route.params.eventToken as string)

const eventIsStored = computed(() => isStored(eventToken.value))

function handleCalendarDownload() {
  if (!event.value) return
  downloadIcal({
    eventToken: event.value.eventToken,
    title: event.value.title,
    dateTime: event.value.dateTime,
    location: event.value.location,
    description: event.value.description,
  })
}

function handleBookmarkClick() {
  if (!event.value) return
  if (isOrganizer.value || rsvpName.value) return
  if (eventIsStored.value) {
    removeEvent(eventToken.value)
  } else {
    saveWatch(eventToken.value, event.value.title, event.value.dateTime)
  }
}

const formattedDateTime = computed(() => {
  if (!event.value) return ''
  const formatted = new Intl.DateTimeFormat(undefined, {
    dateStyle: 'long',
    timeStyle: 'short',
  }).format(new Date(event.value.dateTime))
  return `${formatted} (${event.value.timezone})`
})

async function fetchEvent() {
  state.value = 'loading'
  event.value = null

  try {
    const { data, error, response } = await api.GET('/events/{eventToken}', {
      params: { path: { eventToken: route.params.eventToken as string } },
    })

    if (error) {
      state.value = response.status === 404 ? 'not-found' : 'error'
      return
    }

    event.value = data!
    state.value = 'loaded'

    // Check if current user is the organizer
    const orgToken = getOrganizerToken(event.value.eventToken)
    isOrganizer.value = !!orgToken

    // Fetch attendee list for organizer
    if (orgToken) {
      fetchAttendees(event.value.eventToken, orgToken)
    }

    // Restore RSVP status from localStorage
    const stored = getRsvp(event.value.eventToken)
    if (stored) {
      rsvpName.value = stored.rsvpName
    }
  } catch {
    state.value = 'error'
  }
}

async function submitRsvp() {
  nameError.value = ''
  submitError.value = ''

  if (!nameInput.value) {
    nameError.value = 'Please enter your name.'
    return
  }

  if (nameInput.value.length > 100) {
    nameError.value = 'Name must be 100 characters or fewer.'
    return
  }

  submitting.value = true

  try {
    const { data, error } = await api.POST('/events/{eventToken}/rsvps', {
      params: { path: { eventToken: route.params.eventToken as string } },
      body: { name: nameInput.value },
    })

    if (error) {
      submitError.value = 'Could not submit RSVP. Please try again.'
      return
    }

    // Persist RSVP in localStorage
    saveRsvp(
      event.value!.eventToken,
      data!.rsvpToken,
      data!.name,
      event.value!.title,
      event.value!.dateTime,
    )

    // Update UI
    rsvpName.value = data!.name
    event.value!.attendeeCount += 1
    sheetOpen.value = false
    nameInput.value = ''
  } catch {
    submitError.value = 'Could not submit RSVP. Please try again.'
  } finally {
    submitting.value = false
  }
}

async function handleCancelRsvp() {
  confirmCancelOpen.value = false
  cancelError.value = ''

  const stored = getRsvp(route.params.eventToken as string)
  if (!stored) return

  try {
    const { response } = await api.DELETE('/events/{eventToken}/rsvps/{rsvpToken}', {
      params: {
        path: {
          eventToken: route.params.eventToken as string,
          rsvpToken: stored.rsvpToken,
        },
      },
    })

    if (response.status === 204 || response.status === 404) {
      removeRsvp(route.params.eventToken as string)
      rsvpName.value = undefined
      if (event.value) {
        event.value.attendeeCount = Math.max(0, event.value.attendeeCount - 1)
      }
    } else {
      cancelError.value = 'Could not cancel RSVP. Please try again.'
    }
  } catch {
    cancelError.value = 'Could not cancel RSVP. Please try again.'
  }
}

async function handleCancelEvent() {
  cancelEventError.value = ''
  cancellingEvent.value = true

  const orgToken = getOrganizerToken(route.params.eventToken as string)
  if (!orgToken) return

  try {
    const { error } = await api.PATCH('/events/{eventToken}', {
      params: {
        path: { eventToken: route.params.eventToken as string },
        query: { organizerToken: orgToken },
      },
      body: {
        cancelled: true,
        cancellationReason: cancelReasonInput.value || undefined,
      },
    })

    if (error) {
      cancelEventError.value = 'Could not cancel event. Please try again.'
      return
    }

    cancelSheetOpen.value = false
    cancelReasonInput.value = ''
    await fetchEvent()
  } catch {
    cancelEventError.value = 'Could not cancel event. Please try again.'
  } finally {
    cancellingEvent.value = false
  }
}

async function fetchAttendees(eventToken: string, organizerToken: string) {
  try {
    const { data, error } = await api.GET('/events/{eventToken}/attendees', {
      params: {
        path: { eventToken: eventToken },
        query: { organizerToken },
      },
    })

    if (!error) {
      attendeeNames.value = data!.attendees.map((a) => a.name)
    }
  } catch {
    // Silently degrade — don't show attendee list
  }
}

onMounted(fetchEvent)
</script>

<style scoped>
.detail {
  display: flex;
  flex-direction: column;
  /* Break out of .app-container constraints */
  width: 100dvw;
  flex: 1;
  position: relative;
  left: 50%;
  transform: translateX(-50%);
  margin: calc(-1 * var(--content-padding)) 0;
  overflow-x: hidden;
}

/* Hero image section */
.detail__hero {
  position: relative;
  width: 100%;
  height: 420px;
  overflow: visible;
  flex-shrink: 0;
}

.detail__hero-img {
  position: absolute;
  inset: 0;
  width: 100%;
  height: 100%;
  object-fit: cover;
  mask-image: linear-gradient(to bottom, black 40%, transparent 100%);
  -webkit-mask-image: linear-gradient(to bottom, black 40%, transparent 100%);
}

.detail__hero-overlay {
  position: absolute;
  inset: 0;
  background: linear-gradient(
    to bottom,
    var(--color-glass-overlay) 0%,
    transparent 50%
  );
  pointer-events: none;
}

.detail__body {
  flex: 1;
  padding: var(--spacing-lg) var(--content-padding);
  padding-bottom: 6rem;
}

.detail__content {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-2xl);
  max-width: var(--content-max-width);
  margin: 0 auto;
}

.detail__content--center {
  align-items: center;
  text-align: center;
  padding-top: 4rem;
}

.detail__meta-icon svg {
  display: block;
}

/* Title */
.detail__title {
  font-size: 2rem;
  font-weight: 800;
  color: var(--color-text-on-gradient);
  word-break: break-word;
  line-height: 1.2;
  letter-spacing: -0.02em;
}

/* Meta rows: icon + text */
.detail__meta {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-md);
}

.detail__meta-item {
  display: flex;
  align-items: center;
  gap: var(--spacing-sm);
}

.detail__meta-icon {
  flex-shrink: 0;
  width: 36px;
  height: 36px;
  display: flex;
  align-items: center;
  justify-content: center;
  border-radius: 10px;
  color: var(--color-text-on-gradient);
  line-height: 0;
  background: linear-gradient(135deg, var(--color-glass-strong) 0%, var(--color-glass-subtle) 100%);
  border: 1px solid var(--color-glass-border);
  backdrop-filter: blur(16px);
}

.detail__meta-text {
  font-size: 0.9rem;
  color: var(--color-text-on-gradient);
  word-break: break-word;
}

/* About section */
.detail__section {
  display: flex;
  flex-direction: column;
  gap: var(--spacing-xs);
}

.detail__section-title {
  font-size: 0.75rem;
  font-weight: 700;
  color: var(--color-text-muted);
  text-transform: uppercase;
  letter-spacing: 0.08em;
}

.detail__description {
  font-size: 0.95rem;
  color: var(--color-text-soft);
  line-height: 1.6;
  word-break: break-word;
}

/* Expired banner */
.detail__banner {
  padding: var(--spacing-sm) var(--spacing-md);
  border-radius: 10px;
  font-weight: 600;
  font-size: 0.85rem;
  text-align: center;
}

/* Error / not-found message */
.detail__message {
  font-size: 1.1rem;
  font-weight: 600;
  color: var(--color-text-on-gradient);
}

/* Skeleton – shimmer on gradient */
.skeleton {
  background: linear-gradient(90deg, var(--color-glass) 25%, var(--color-glass-hover) 50%, var(--color-glass) 75%);
  background-size: 200% 100%;
}

.skeleton--title {
  height: 2rem;
  width: 70%;
  border-radius: 8px;
}

.skeleton--line {
  height: 1rem;
  width: 85%;
  border-radius: 6px;
}

.skeleton--short {
  width: 45%;
}

/* RSVP submit button (glow border wrapper) */
.rsvp-form__submit {
  width: 100%;
  border-radius: var(--radius-button);
  transition: transform 0.1s ease;
}

.rsvp-form__submit:hover {
  transform: scale(1.02);
}

.rsvp-form__submit:active {
  transform: scale(0.98);
}

.rsvp-form__submit-inner {
  display: block;
  width: 100%;
  padding: var(--spacing-md) var(--spacing-lg);
  border-radius: calc(var(--radius-button) - 2px);
  font-family: inherit;
  font-size: 1rem;
  font-weight: 700;
  color: var(--color-text-on-gradient);
  text-align: center;
  border: none;
  cursor: pointer;
}

.rsvp-form__submit-inner:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

/* Cancellation banner */
.detail__cancelled-banner {
  padding: var(--spacing-md) var(--spacing-lg);
  border-radius: var(--radius-card);
  background: var(--color-danger-bg);
  border: 1px solid var(--color-danger-border-strong);
  text-align: center;
}

.detail__cancelled-banner-title {
  font-weight: 700;
  font-size: 0.95rem;
  color: var(--color-danger);
}

.detail__cancelled-banner-reason {
  margin-top: var(--spacing-xs);
  font-size: 0.85rem;
  color: var(--color-text-soft);
  word-break: break-word;
}

/* Kebab menu (teleported into app header) */
.detail__kebab-wrapper {
  position: relative;
}

.detail__kebab-btn {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 48px;
  height: 48px;
  border-radius: 12px;
  background: none;
  border: none;
  color: var(--color-text-on-gradient);
  cursor: pointer;
  transition: background 0.15s ease;
  -webkit-tap-highlight-color: transparent;
}

.detail__kebab-btn:hover {
  background: var(--color-glass-hover);
}

.detail__kebab-menu {
  position: absolute;
  top: calc(100% + var(--spacing-xs));
  right: 0;
  min-width: 180px;
  padding: var(--spacing-xs) 0;
  border-radius: var(--radius-card);
  background: linear-gradient(135deg, var(--color-glass-strong) 0%, var(--color-glass-subtle) 100%);
  border: 1px solid var(--color-glass-border);
  backdrop-filter: blur(16px);
  box-shadow: var(--shadow-card);
}

.detail__kebab-item {
  display: block;
  width: 100%;
  padding: var(--spacing-sm) var(--spacing-lg);
  font-family: inherit;
  font-size: 0.9rem;
  font-weight: 600;
  color: var(--color-text-on-gradient);
  background: none;
  border: none;
  cursor: pointer;
  text-align: left;
  transition: background 0.15s ease;
}

.detail__kebab-item:hover {
  background: var(--color-glass-hover);
}

.detail__kebab-item--danger {
  color: var(--color-danger);
}

.kebab-menu-enter-active,
.kebab-menu-leave-active {
  transition: opacity 0.15s ease, transform 0.15s ease;
}

.kebab-menu-enter-from,
.kebab-menu-leave-to {
  opacity: 0;
  transform: translateY(-4px);
}

/* Organizer bottom bar — mirrors RsvpBar layout */
.detail__organizer-bar {
  position: fixed;
  bottom: 0;
  left: 0;
  right: 0;
  display: flex;
  justify-content: center;
  z-index: 10;
  padding: var(--spacing-md) var(--content-padding);
  padding-bottom: calc(var(--spacing-md) + env(safe-area-inset-bottom, 0px));
}

.detail__organizer-bar-inner {
  width: 100%;
  max-width: var(--content-max-width);
  display: flex;
  gap: var(--spacing-sm);
}


/* Cancel event form (inside bottom sheet) */
.cancel-form__textarea {
  resize: vertical;
  min-height: 4rem;
  font-family: inherit;
}

.cancel-form__counter {
  display: block;
  text-align: right;
  font-size: 0.75rem;
  color: var(--color-text-muted);
  margin-top: var(--spacing-xs);
}

.cancel-form__confirm {
  display: block;
  width: 100%;
  margin-top: var(--spacing-md);
  padding: var(--spacing-md) var(--spacing-lg);
  border-radius: var(--radius-button);
  font-family: inherit;
  font-size: 1rem;
  font-weight: 700;
  color: var(--color-danger-solid-text);
  background: var(--color-danger-solid);
  border: none;
  cursor: pointer;
  transition: background 0.15s ease;
}

.cancel-form__confirm:hover {
  background: var(--color-danger-solid-hover);
}

.cancel-form__confirm:disabled {
  opacity: 0.6;
  cursor: not-allowed;
}

.cancel-form__error {
  margin-top: var(--spacing-sm);
  font-size: 0.85rem;
  color: var(--color-danger);
  text-align: center;
}
</style>
