<template>
  <BasicModal
    title="جزئیات تیکت"
    title-en="Ticket Details"
    width="95%"
    max-width="64rem"
    min-width="auto"
    :show-close-button="true"
  >
    <template #default>
      <div class="ticket-details">
        <div v-if="ticket" class="ticket-details__date">
          <span>{{ ticketDate }}</span>
        </div>

        <SkeletonLoaderBlock v-if="isLoading && !ticket" :rows="3" :cols-per-row="1" />
        <div
          v-else-if="messages.length > 0 || ticketMedia.length > 0"
          class="ticket-details__thread"
          ref="thread"
        >
          <div v-if="ticketMedia.length > 0" class="ticket-details__row ticket-details__row--user">
            <div class="ticket-details__bubble">
              <MessageAttachments :media="ticketMedia" />
              <span class="ticket-details__time">{{ messageTime(ticket) }}</span>
            </div>
          </div>
          <div
            v-for="message in messages"
            :key="message.id"
            class="ticket-details__row"
            :class="`ticket-details__row--${senderClass(message)}`"
          >
            <div class="ticket-details__bubble">
              <MessageAttachments v-if="message.media?.length" :media="message.media" />
              <p class="ticket-details__text">{{ message.message }}</p>
              <span class="ticket-details__time">{{ messageTime(message) }}</span>
            </div>
          </div>
        </div>
        <NoItems v-else title="پیامی نیست" desc="هنوز پیامی در این تیکت ثبت نشده است." />

        <div class="ticket-details__divider" />

        <div v-if="attachments.length > 0" class="ticket-details__attachments">
          <span
            v-for="(file, index) in attachments"
            :key="file.id ?? index"
            class="ticket-details__attachment"
          >
            <SvgIcon name="file" :size="14" color="currentColor" />
            <span class="ticket-details__attachment-name">{{ file.name }}</span>
            <button
              type="button"
              class="ticket-details__attachment-remove"
              aria-label="حذف فایل"
              @click="removeAttachment(index)"
            >
              <SvgIcon name="close" :size="12" color="var(--color-error)" />
            </button>
          </span>
        </div>

        <form class="ticket-details__compose" @submit.prevent="onSend">
          <button
            type="submit"
            :disabled="!canSend"
            class="ticket-details__send"
            aria-label="ارسال"
          >
            <SvgIcon name="paper-plane-right" :size="22" color="var(--color-primary)" />
          </button>
          <input
            v-model="text"
            type="text"
            placeholder="ارسال پیام"
            class="ticket-details__input"
          />
          <div class="ticket-details__compose-actions">
            <button
              ref="emojiButton"
              type="button"
              class="ticket-details__compose-btn"
              :class="{ 'ticket-details__compose-btn--active': emojiOpen }"
              aria-label="ایموجی"
              @click="toggleEmoji"
            >
              <SvgIcon name="mood" :size="30" color="currentColor" />
            </button>
            <button
              type="button"
              class="ticket-details__compose-btn"
              :disabled="uploadMutation.isPending.value"
              aria-label="پیوست فایل"
              @click="fileInput?.click()"
            >
              <SvgIcon name="attach-file" :size="30" color="currentColor" />
            </button>
            <input
              ref="fileInput"
              type="file"
              class="ticket-details__file-input"
              accept="image/*,application/pdf"
              multiple
              @change="onFilesPicked"
            />
          </div>
        </form>
      </div>
    </template>
  </BasicModal>

  <Teleport to="body">
    <Transition name="emoji-pop">
      <div v-if="emojiOpen" ref="emojiPanel" class="ticket-emoji-panel" :style="emojiStyle">
        <button
          v-for="emoji in EMOJIS"
          :key="emoji"
          type="button"
          class="ticket-emoji-panel__emoji"
          @click="insertEmoji(emoji)"
        >
          {{ emoji }}
        </button>
      </div>
    </Transition>
  </Teleport>
</template>

<script setup>
import { toast } from 'vue3-toastify'
import useModal from '@/composables/useModal'
import { useQueryClient } from '@tanstack/vue-query'
import BasicModal from '@/components/BasicModal.vue'
import SvgIcon from '@/components/icons/SvgIcon.vue'
import NoItems from '@/components/blocks/NoItems.vue'
import { formatJalaaliDate } from '@/utils/date-utils'
import { objectToFormData } from '@/utils/object-to-formdata'
import { useUploadMediaMutation } from '@/services/query/auth'
import { computed, nextTick, onBeforeUnmount, ref, watch } from 'vue'
import MessageAttachments from '@/components/blocks/MessageAttachments.vue'
import SkeletonLoaderBlock from '@/components/blocks/SkeletonLoaderBlock.vue'
import {
  autoUpdate,
  computePosition,
  flip,
  offset as offsetMiddleware,
  shift,
} from '@floating-ui/dom'
import {
  adminTicketsKeys,
  useAdminTicketQuery,
  useSendAdminTicketMessageMutation,
} from '@/services/query/admin-tickets'

defineOptions({ name: 'TicketDetailsModal' })

const EMOJIS = [
  '😀',
  '😂',
  '😍',
  '🤔',
  '👍',
  '👎',
  '🙏',
  '👏',
  '🎉',
  '🔥',
  '✨',
  '⭐',
  '✅',
  '❌',
  '❤️',
  '💔',
  '😊',
  '😎',
  '😢',
  '😡',
  '🤝',
  '👌',
  '💡',
  '📌',
]

const queryClient = useQueryClient()
const { getModal } = useModal()

const modalData = computed(() => getModal('TicketDetailsModal')?.data ?? {})
const ticketId = computed(() => modalData.value.id ?? null)

const { data: ticket, isLoading } = useAdminTicketQuery(ticketId, {
  enabled: () => !!ticketId.value,
})

const messages = computed(() => ticket.value?.messages ?? [])

const ticketMedia = computed(() => ticket.value?.media ?? [])

const ticketDate = computed(() => formatJalaaliDate(ticket.value?.createdAt) || '—')

// Anyone whose id matches the ticket's student is "the student"; everyone else
// (admin, counselor) renders on the opposite side of the thread.
const senderClass = (message) => (message.senderId === ticket.value?.studentId ? 'user' : 'admin')

const messageTime = (message) => {
  if (!message.createdAt) return '—'
  const d = new Date(message.createdAt)
  if (Number.isNaN(d.getTime())) return '—'
  return d.toLocaleTimeString('fa-IR', { hour: '2-digit', minute: '2-digit' })
}

const text = ref('')

const MAX_ATTACHMENTS = 5

const fileInput = ref(null)
const attachments = ref([])

const uploadMutation = useUploadMediaMutation()

const onFilesPicked = async (event) => {
  const picked = [...event.target.files]
  event.target.value = ''
  if (attachments.value.length + picked.length > MAX_ATTACHMENTS) {
    toast.warning(`حداکثر تعداد فایل مجاز ${MAX_ATTACHMENTS} عدد است.`)
    return
  }
  for (const file of picked) {
    try {
      const fd = objectToFormData({ file, purpose: 'attachment', context: 'ticket' })
      const response = await uploadMutation.mutateAsync(fd)
      const payload = response?.data ?? response
      const id = payload?.id ?? payload?.uploadId
      if (id == null) continue
      attachments.value = [
        ...attachments.value,
        { id, name: file.name, size: file.size, url: payload?.url ?? '' },
      ]
    } catch {
      toast.error(`بارگذاری فایل "${file.name}" با خطا مواجه شد.`)
    }
  }
}

const removeAttachment = (index) => {
  const next = [...attachments.value]
  next.splice(index, 1)
  attachments.value = next
}

const canSend = computed(
  () =>
    (text.value.trim().length > 0 || attachments.value.length > 0) &&
    !uploadMutation.isPending.value
)

const emojiOpen = ref(false)
const emojiButton = ref(null)
const emojiPanel = ref(null)
const emojiStyle = ref({ position: 'fixed', top: '0', left: '0' })
let emojiCleanup = null

const toggleEmoji = () => {
  emojiOpen.value = !emojiOpen.value
}
const insertEmoji = (emoji) => {
  text.value += emoji
}

const mountEmoji = async () => {
  await nextTick()
  if (!emojiButton.value || !emojiPanel.value) return
  emojiCleanup = autoUpdate(emojiButton.value, emojiPanel.value, () => {
    computePosition(emojiButton.value, emojiPanel.value, {
      placement: 'top-end',
      strategy: 'fixed',
      middleware: [offsetMiddleware(8), flip(), shift({ padding: 8 })],
    }).then(({ x, y }) => {
      emojiStyle.value = { position: 'fixed', top: `${y}px`, left: `${x}px` }
    })
  })
}

const unmountEmoji = () => {
  emojiCleanup?.()
  emojiCleanup = null
}

watch(emojiOpen, (open) => {
  if (open) mountEmoji()
  else unmountEmoji()
})

const onDocumentClick = (event) => {
  if (!emojiOpen.value) return
  if (emojiPanel.value?.contains(event.target)) return
  if (emojiButton.value?.contains(event.target)) return
  emojiOpen.value = false
}
document.addEventListener('mousedown', onDocumentClick)
onBeforeUnmount(() => {
  document.removeEventListener('mousedown', onDocumentClick)
  unmountEmoji()
})

const sendMutation = useSendAdminTicketMessageMutation()

const onSend = async () => {
  if (!canSend.value || !ticketId.value) return
  const value = text.value.trim()
  const mediaIds = attachments.value.map((f) => f.id).filter((id) => id != null)
  text.value = ''
  attachments.value = []
  emojiOpen.value = false
  // Backend POST /admin/tickets/:id/messages — body is { message: string,
  // mediaIds?: number[] } where mediaIds reference previously uploaded media.
  const payload = { message: value }
  if (mediaIds.length > 0) payload.mediaIds = mediaIds
  await sendMutation.mutateAsync({ id: ticketId.value, payload })
  await queryClient.invalidateQueries({ queryKey: adminTicketsKeys.all })
}

const thread = ref(null)

watch(messages, async () => {
  await nextTick()
  if (thread.value) {
    thread.value.scrollTop = thread.value.scrollHeight
  }
})
</script>

<style lang="scss" scoped>
.ticket-details {
  width: 100%;
  text-align: start;
  display: flex;
  flex-direction: column;
  max-height: calc(100dvh - 8rem);
  min-height: 28rem;

  &__date {
    display: flex;
    justify-content: center;
    margin: 0.5rem 0 0.875rem;
  }

  &__date span {
    background: #f7f7f7;
    color: #9c9c9c;
    border-radius: 9999px;
    padding: 0.5rem 1.25rem;
    font-family: var(--font-family-en);
    font-size: 0.75rem;
  }

  &__thread {
    flex: 1;
    min-height: 0;
    overflow-y: auto;
    display: flex;
    flex-direction: column;
    gap: 0.75rem;
    padding-block: 0.5rem 1rem;
    padding-inline-end: 0.25rem;
  }

  &__row {
    display: flex;

    &--admin {
      justify-content: flex-start;
    }

    &--user {
      justify-content: flex-end;
    }
  }

  &__bubble {
    max-width: 72%;
    border-radius: 1rem;
    padding: 0.75rem 1.25rem;

    .ticket-details__row--admin & {
      background: var(--color-primary);
      color: #fff;
      border-end-start-radius: 0;
    }

    .ticket-details__row--user & {
      background: #f8f8f8;
      color: #5d5d5d;
      border-end-end-radius: 0;
    }
  }

  &__text {
    font-family: var(--font-family-fa);
    font-size: 0.875rem;
    line-height: 1.7;
    margin: 0;
  }

  &__time {
    display: block;
    margin-top: 0.375rem;
    font-family: var(--font-family-en);
    font-size: 0.7rem;

    .ticket-details__row--admin & {
      color: rgba(255, 255, 255, 80%);
    }

    .ticket-details__row--user & {
      color: #b1b1b1;
    }
  }

  &__divider {
    border-block-end: 1px solid var(--color-thd-gray);
    margin-block: 0.75rem;
  }

  &__compose {
    flex-shrink: 0;
    display: flex;
    align-items: center;
    gap: 0.5rem;
  }

  &__send {
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 9999px;
    border: none;
    background: transparent;
    color: var(--color-primary);
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.2s ease;

    &:hover:enabled {
      background: var(--color-primary);
      color: #fff;
    }

    &:disabled {
      opacity: 0.4;
      cursor: not-allowed;
    }
  }

  &__input {
    flex: 1;
    height: 2.5rem;
    border: 1px solid transparent;
    border-radius: 1.5rem;
    padding: 0 1rem;
    font-family: var(--font-family-fa);
    font-size: 0.875rem;
    color: #4b4b4b;
    outline: none;

    &:focus {
      border-color: var(--color-thd-gray);
    }
  }

  &__compose-actions {
    position: relative;
    display: flex;
    align-items: center;
    gap: 0.25rem;
    flex-shrink: 0;
  }

  &__compose-btn {
    width: 2.5rem;
    height: 2.5rem;
    border-radius: 9999px;
    border: none;
    background: transparent;
    color: #d1d1d1;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: background 0.15s ease, color 0.15s ease;

    &:hover {
      background: rgba(0, 0, 0, 4%);
      color: var(--color-prim-gray);
    }

    &--active {
      color: var(--color-primary);
      background: rgba(0, 0, 0, 4%);
    }
  }

  &__file-input {
    display: none;
  }

  &__attachments {
    display: flex;
    flex-wrap: wrap;
    gap: 0.375rem;
  }

  &__attachment {
    display: inline-flex;
    align-items: center;
    gap: 0.375rem;
    padding: 0.375rem 0.625rem;
    margin-bottom: 0.5rem;
    background: #f7f7f7;
    border-radius: 9999px;
    align-self: flex-start;
    font-family: var(--font-family-fa);
    font-size: 0.75rem;
    color: #4b4b4b;
    max-width: 18rem;
  }

  &__attachment-name {
    overflow: hidden;
    text-overflow: ellipsis;
    white-space: nowrap;
    flex: 1;
    min-width: 0;
  }

  &__attachment-remove {
    border: none;
    background: transparent;
    cursor: pointer;
    padding: 0;
    display: flex;
    align-items: center;
    justify-content: center;
  }
}

.ticket-emoji-panel {
  width: 17rem;
  background: #fff;
  border-radius: 0.875rem;
  box-shadow: 0 10px 25px -8px rgba(0, 0, 0, 12%), 0 4px 10px -4px rgba(0, 0, 0, 8%);
  padding: 0.5rem;
  display: grid;
  grid-template-columns: repeat(8, 1fr);
  gap: 0.125rem;
  z-index: 1000;

  &__emoji {
    height: 2rem;
    border: none;
    background: transparent;
    border-radius: 0.5rem;
    cursor: pointer;
    font-size: 1.125rem;
    line-height: 1;

    &:hover {
      background: #f3f4f6;
    }
  }
}

.emoji-pop-enter-active,
.emoji-pop-leave-active {
  transition: opacity 0.12s ease, transform 0.12s ease;
}

.emoji-pop-enter-from,
.emoji-pop-leave-to {
  opacity: 0;
  transform: translateY(6px);
}
</style>
