<script setup lang="ts">
import { ref, computed, watch, onUnmounted } from 'vue'
import { presignDownload } from '@/core/api'
import { useLocalTranslation } from '@/lib/composables/useLocalTranslation'
import AgentResponse from '@/components/ui/AgentResponse.vue'
import ImageAttachment from '@/components/ui/ImageAttachment.vue'
import ImagePreviewDialog from '@/components/ui/ImagePreviewDialog.vue'
import ChatWindowFooter from './ChatWindowFooter.vue'
import TypingIndicator from './TypingIndicator.vue'
import InChatReview from './InChatReview.vue'
import PoweredBy from '@/ui/PoweredBy.vue'
import SeperatorIcon from '@/assets/seperator.svg'
import LogoIcon from '@/assets/logo.svg'
import SolarUserBold from '~icons/solar/user-bold'
import type { Message, ReviewProps } from '@/lib/types'

const props = withDefaults(defineProps<{
  onSendMessage: (message: string, attachmentIds: string[]) => void
  onEnsureSession: () => Promise<string>
  messages: Message[]
  assistantStatus?: string
  needsAgent: boolean
  sessionId?: string | null
  isChatClosed?: boolean
  inChatReviewSessionId?: string | null
  isSubmittingReview?: boolean
  onInChatReviewSubmit?: (payload: ReviewProps) => void | Promise<void>
  onInChatReviewDone?: () => void
}>(), { assistantStatus: 'loading', isChatClosed: false, isSubmittingReview: false })

const { i18n } = useLocalTranslation()
const inputMessage = ref('')
const messagesEndRef = ref<HTMLDivElement | null>(null)
const scrollTimeoutRef = ref<ReturnType<typeof setTimeout> | null>(null)
const lastMessageCount = ref(props.messages.length)
const galleryState = ref<{ isOpen: boolean; imageUrls: string[]; initialIndex: number }>({
  isOpen: false,
  imageUrls: [],
  initialIndex: 0,
})

function scrollToBottom() {
  if (scrollTimeoutRef.value) clearTimeout(scrollTimeoutRef.value)
  scrollTimeoutRef.value = setTimeout(() => {
    messagesEndRef.value?.scrollIntoView({ behavior: 'smooth', block: 'end' })
  }, 100)
}

watch(
  () => [props.messages.length, props.assistantStatus] as const,
  ([len, status]) => {
    if (len !== lastMessageCount.value || status === 'typing') {
      lastMessageCount.value = len
      scrollToBottom()
    }
  }
)

onUnmounted(() => { if (scrollTimeoutRef.value) clearTimeout(scrollTimeoutRef.value) })

function handleSendMessage(attachmentIds: string[]) {
  if (inputMessage.value.trim() || attachmentIds.length > 0) {
    props.onSendMessage(inputMessage.value, attachmentIds)
    inputMessage.value = ''
  }
}

const firstHumanAgentIndex = computed(() => props.messages.findIndex((m) => m.senderType === 2))
const hasHumanAgent = computed(() => props.needsAgent || props.messages.some((m) => m.senderType === 2))
const isLoading = computed(() => {
  if (hasHumanAgent.value) return false
  return props.assistantStatus === 'typing' || props.assistantStatus === 'loading' || props.assistantStatus === 'error'
})
const showInChatReview = computed(() => !!props.inChatReviewSessionId && !!props.onInChatReviewSubmit)

async function handleImageClick(attachmentIdsOrUrls: string[], clickedIndex: number) {
  if (!attachmentIdsOrUrls?.length) return
  try {
    const isUrl = attachmentIdsOrUrls[0]?.startsWith('http://') || attachmentIdsOrUrls[0]?.startsWith('https://')
    let imageUrls: string[]

    if (isUrl) {
      imageUrls = attachmentIdsOrUrls.filter((u): u is string => !!u)
      if (imageUrls.length > 0) {
        galleryState.value = { isOpen: true, imageUrls, initialIndex: Math.max(0, Math.min(clickedIndex, imageUrls.length - 1)) }
      }
      return
    }

    const results = await Promise.all(
      attachmentIdsOrUrls.map((id) =>
        id
          ? presignDownload(id, i18n.language as 'ar' | 'en').then((r) => r.downloadUrl || null).catch(() => null)
          : Promise.resolve(null)
      )
    )
    imageUrls = results.filter((u): u is string => !!u)
    if (imageUrls.length > 0) {
      galleryState.value = { isOpen: true, imageUrls, initialIndex: Math.max(0, Math.min(clickedIndex, imageUrls.length - 1)) }
    }
  } catch { /* silent */ }
}
</script>

<template>
  <div class="babylai:flex-1 babylai:overflow-y-auto babylai:p-4 babylai:h-full">
    <template v-for="(message, index) in messages" :key="`${message.id}-${index}`">
      <div>
        <!-- Human agent separator -->
        <div v-if="index === firstHumanAgentIndex && message.senderType === 2" class="babylai:flex babylai:justify-center babylai:items-center babylai:my-4">
          <SeperatorIcon class="babylai:w-full babylai:text-primary-500" />
        </div>

        <div :class="['babylai:mb-4 babylai:flex', message.senderType === 1 ? 'babylai:justify-end' : 'babylai:justify-start']">
          <!-- Avatar -->
          <div
            v-if="(index === 0 || messages[index - 1].senderType !== message.senderType) && (message.senderType === 3 || message.senderType === 2)"
            class="babylai:shrink-0 babylai:me-3"
          >
            <div :class="['babylai:w-8 babylai:h-8 babylai:rounded-full babylai:flex babylai:items-center babylai:justify-center', message.senderType === 3 ? 'babylai:bg-primary' : 'babylai:bg-black-white-50']">
              <LogoIcon v-if="message.senderType === 3" class="babylai:w-4 babylai:h-4 babylai:text-primary" />
              <SolarUserBold v-else class="babylai:w-4 babylai:h-4 babylai:text-primary" />
            </div>
          </div>
          <div v-else-if="message.senderType !== 1" class="babylai:shrink-0 babylai:me-3 babylai:w-8" />

          <div class="babylai:flex babylai:flex-col babylai:gap-2">
            <!-- Attachment URLs (from Ably) -->
            <div v-if="message.attachmentUrls?.length" class="babylai:flex babylai:flex-row babylai:flex-wrap babylai:gap-2 babylai:max-w-full">
              <ImageAttachment
                v-for="(url, imgIdx) in message.attachmentUrls"
                :key="url"
                :image-url="url"
                :enable-preview="false"
                @click="handleImageClick(message.attachmentUrls!, imgIdx)"
              />
            </div>
            <!-- Attachment IDs (user-sent) -->
            <div v-if="message.attachmentIds?.length" class="babylai:flex babylai:flex-row babylai:flex-wrap babylai:gap-2 babylai:max-w-full">
              <ImageAttachment
                v-for="(id, imgIdx) in message.attachmentIds"
                :key="id"
                :file-id="id"
                :enable-preview="false"
                @click="handleImageClick(message.attachmentIds!, imgIdx)"
              />
            </div>
            <!-- Message content -->
            <AgentResponse
              v-if="message.messageContent?.trim()"
              :message-content="message.messageContent"
              :sender-type="message.senderType"
              :message-id="message.id"
              :on-type="scrollToBottom"
            />
          </div>
        </div>
      </div>
    </template>

    <TypingIndicator v-if="assistantStatus === 'typing'" :first-human-agent-index="firstHumanAgentIndex" />

    <template v-if="showInChatReview">
      <SeperatorIcon class="babylai:my-6 babylai:text-black-white-300" />
      <InChatReview
        :on-submit="onInChatReviewSubmit!"
        :on-done="onInChatReviewDone"
        :is-submitting="isSubmittingReview"
      />
    </template>

    <div ref="messagesEndRef" />
  </div>

  <ChatWindowFooter
    :input-message="inputMessage"
    :is-loading="isLoading"
    :is-chat-closed="isChatClosed"
    :session-id="sessionId"
    :on-ensure-session="onEnsureSession"
    :handle-send-message="handleSendMessage"
    @update:input-message="inputMessage = $event"
  />

  <PoweredBy />

  <ImagePreviewDialog
    v-if="galleryState.isOpen && galleryState.imageUrls.length > 0"
    :image-urls="galleryState.imageUrls"
    :initial-index="galleryState.initialIndex"
    :is-open="galleryState.isOpen"
    alt="Image gallery preview"
    @close="galleryState = { isOpen: false, imageUrls: [], initialIndex: 0 }"
  />
</template>
