<script setup lang="ts">
import { ref, computed } from 'vue'
import axios from 'axios'
import { useLocalTranslation } from '@/lib/composables/useLocalTranslation'
import { presignUpload } from '@/core/api'
import ImagePreviewDialog from '@/components/ui/ImagePreviewDialog.vue'
import MaterialSymbolsCloseSmallOutlineRounded from '~icons/material-symbols/close-small-outline-rounded'
import SolarPlain2BoldDuotone from '~icons/solar/plain-2-bold-duotone'
import SolarPaperclipBoldDuotone from '~icons/solar/paperclip-bold-duotone'

interface SelectedFileDto {
  file: File
  previewUrl: string
  uploading: boolean
  uploadedId: string | null
  error: string | null
}

const props = defineProps<{
  inputMessage: string
  isLoading: boolean
  isChatClosed?: boolean
  sessionId?: string | null
  onEnsureSession: () => Promise<string>
  handleSendMessage: (attachmentIds: string[]) => void
}>()

defineEmits<{ 'update:inputMessage': [value: string] }>()

const { t, i18n } = useLocalTranslation()
const fileInputRef = ref<HTMLInputElement | null>(null)
const selectedFiles = ref<SelectedFileDto[]>([])
const previewImage = ref<string | null>(null)
const isSending = ref(false)

function handleAttachClick() { fileInputRef.value?.click() }

function handleFileSelect(e: Event) {
  const files = Array.from((e.target as HTMLInputElement).files || [])
  const imageFiles = files.filter((f) => f.type.startsWith('image/'))
  const newFiles: SelectedFileDto[] = imageFiles.map((file) => ({
    file,
    previewUrl: URL.createObjectURL(file),
    uploading: false,
    uploadedId: null,
    error: null,
  }))
  selectedFiles.value = [...selectedFiles.value, ...newFiles]
  if (fileInputRef.value) fileInputRef.value.value = ''
}

function handleRemoveFile(previewUrl: string) {
  const file = selectedFiles.value.find((f) => f.previewUrl === previewUrl)
  if (file) URL.revokeObjectURL(file.previewUrl)
  selectedFiles.value = selectedFiles.value.filter((f) => f.previewUrl !== previewUrl)
}

async function handleSendMessageWithAttachments() {
  if (props.isLoading || props.isChatClosed || isSending.value) return
  isSending.value = true

  try {
    const filesToUpload = selectedFiles.value.filter((f) => f.uploadedId === null && !f.error)
    const alreadyUploadedIds = selectedFiles.value.filter((f) => f.uploadedId !== null).map((f) => f.uploadedId as string)
    let uploadedIds: string[] = []

    if (filesToUpload.length > 0) {
      let sessionId: string | null = null
      try {
        sessionId = props.sessionId || (await props.onEnsureSession())
      } catch {
        selectedFiles.value = selectedFiles.value.map((f) =>
          filesToUpload.some((ftl) => ftl.previewUrl === f.previewUrl)
            ? { ...f, error: 'Failed to initialize session', uploading: false }
            : f
        )
        isSending.value = false
        return
      }

      let hasUploadErrors = false
      for (const fileDto of filesToUpload) {
        try {
          selectedFiles.value = selectedFiles.value.map((f) =>
            f.previewUrl === fileDto.previewUrl ? { ...f, uploading: true, error: null } : f
          )
          const presignResponse = await presignUpload(sessionId, fileDto.file, i18n.language as 'ar' | 'en')
          const uploadResponse = await axios.put(presignResponse.uploadUrl, fileDto.file, {
            headers: { 'Content-Type': fileDto.file.type },
          })
          if (uploadResponse.status !== 200 && uploadResponse.status !== 204) throw new Error(`Upload failed: ${uploadResponse.status}`)
          uploadedIds.push(presignResponse.id)
          selectedFiles.value = selectedFiles.value.map((f) =>
            f.previewUrl === fileDto.previewUrl ? { ...f, uploading: false, uploadedId: presignResponse.id, error: null } : f
          )
        } catch {
          hasUploadErrors = true
          selectedFiles.value = selectedFiles.value.map((f) =>
            f.previewUrl === fileDto.previewUrl ? { ...f, uploading: false, error: 'Upload failed', uploadedId: null } : f
          )
        }
      }
      if (hasUploadErrors) { isSending.value = false; return }
    }

    const allAttachmentIds = [...alreadyUploadedIds, ...uploadedIds]
    props.handleSendMessage(allAttachmentIds)
    selectedFiles.value.forEach((f) => URL.revokeObjectURL(f.previewUrl))
    selectedFiles.value = []
    isSending.value = false
  } catch {
    isSending.value = false
  }
}

function handleKeyDown(e: KeyboardEvent) {
  if (e.key === 'Enter' && !e.shiftKey) {
    e.preventDefault()
    if (!isSendDisabled.value) handleSendMessageWithAttachments()
  }
}

const hasUploadingFiles = computed(() => selectedFiles.value.some((f) => f.uploading))
const hasFileErrors = computed(() => selectedFiles.value.some((f) => f.error !== null))
const hasContentToSend = computed(() => props.inputMessage.trim() !== '' || selectedFiles.value.length > 0)
const isSendDisabled = computed(() =>
  props.isLoading || !!props.isChatClosed || isSending.value || !hasContentToSend.value || hasUploadingFiles.value || hasFileErrors.value
)
const showLoading = computed(() => props.isLoading || isSending.value || hasUploadingFiles.value)
</script>

<template>
  <footer class="babylai:flex babylai:flex-col babylai:gap-2 babylai:mx-4 babylai:mb-2">
    <div v-if="selectedFiles.length > 0" class="babylai:flex babylai:gap-2 babylai:flex-wrap babylai:p-2 babylai:bg-card babylai:rounded-lg">
      <div v-for="file in selectedFiles" :key="file.previewUrl" class="babylai:relative babylai:group">
        <img
          :src="file.previewUrl"
          alt="Preview"
          class="babylai:w-16 babylai:h-16 babylai:object-cover babylai:rounded-lg babylai:border babylai:border-black-white-200 babylai:cursor-pointer babylai:hover:opacity-80 babylai:transition-opacity"
          role="button"
          aria-label="Click to preview image"
          @click="previewImage = file.previewUrl"
        />
        <div v-if="file.uploading" class="babylai:absolute babylai:inset-0 babylai:flex babylai:items-center babylai:justify-center babylai:bg-black babylai:bg-opacity-50 babylai:rounded-lg">
          <div class="babylai:animate-spin babylai:rounded-full babylai:h-6 babylai:w-6 babylai:border-2 babylai:border-white babylai:border-t-transparent" />
        </div>
        <div v-if="file.error" class="babylai:absolute babylai:inset-0 babylai:flex babylai:items-center babylai:justify-center babylai:bg-red-500 babylai:bg-opacity-70 babylai:rounded-lg">
          <span class="babylai:text-white babylai:text-xs">Error</span>
        </div>
        <button
          class="babylai:border-0 babylai:p-0 babylai:absolute babylai:-top-2 babylai:-right-2 babylai:bg-destructive babylai:text-white babylai:rounded-full babylai:w-5 babylai:h-5 babylai:flex babylai:items-center babylai:justify-center babylai:cursor-pointer"
          type="button"
          aria-label="Remove image"
          @click="handleRemoveFile(file.previewUrl)"
        >
          <MaterialSymbolsCloseSmallOutlineRounded class="babylai:w-3 babylai:h-3" />
        </button>
      </div>
    </div>

    <div class="babylai:flex babylai:items-center babylai:gap-2 babylai:relative babylai:rounded-full babylai:bg-card babylai:py-3 babylai:px-4">
      <input type="file" ref="fileInputRef" accept="image/*" multiple class="babylai:hidden" @change="handleFileSelect" />
      <div class="babylai:border-e babylai:border-border babylai:pe-2">
        <button
          :disabled="isLoading || !!isChatClosed"
          class="babylai:flex babylai:items-center babylai:justify-center babylai:border-0 babylai:rounded-full babylai:w-8 babylai:h-8 babylai:cursor-pointer babylai:bg-secondary babylai:text-muted-foreground babylai:hover:text-primary-500 babylai:transition-colors babylai:disabled:opacity-50 babylai:disabled:cursor-not-allowed"
          type="button"
          aria-label="Attach image"
          @click="handleAttachClick"
        >
          <SolarPaperclipBoldDuotone class="babylai:w-4 babylai:h-4" />
        </button>
      </div>
      <input
        type="text"
        :value="inputMessage"
        :placeholder="t('homeSdk.placeholder')"
        :disabled="!!isChatClosed"
        class="babylai:flex-1 babylai:py-2 babylai:px-2 babylai:bg-transparent babylai:outline-none babylai:text-sm babylai:border-none babylai:text-card-foreground babylai:disabled:opacity-50 babylai:disabled:cursor-not-allowed"
        @input="$emit('update:inputMessage', ($event.target as HTMLInputElement).value)"
        @keydown="handleKeyDown"
      />
      <button
        :disabled="isSendDisabled || !!isChatClosed"
        class="babylai:border-0 babylai:rounded-full babylai:bg-primary-500 babylai:hover:bg-primary-600 babylai:w-8 babylai:h-8 babylai:p-0 babylai:flex babylai:items-center babylai:justify-center babylai:disabled:opacity-50 babylai:text-white babylai:cursor-pointer babylai:disabled:cursor-not-allowed"
        type="button"
        @click="handleSendMessageWithAttachments"
      >
        <div v-if="showLoading" class="babylai:inline-block babylai:animate-spin babylai:rounded-full babylai:h-4 babylai:w-4 babylai:border-2 babylai:border-white babylai:border-t-transparent babylai:box-border" />
        <SolarPlain2BoldDuotone v-else class="babylai:w-4 babylai:h-4" />
      </button>
    </div>

    <ImagePreviewDialog
      v-if="previewImage"
      :image-urls="[previewImage]"
      :initial-index="0"
      :is-open="!!previewImage"
      alt="Image preview"
      @close="previewImage = null"
    />
  </footer>
</template>
