<template>
  <!-- WRAPPER: handles drag/drop for the whole area -->
  <div
    class="relative overflow-visible h-full"
    @dragenter.prevent="onDragEnter"
    @dragover.prevent="noop"
    @dragleave.prevent="onDragLeave"
    @drop.prevent="onZoneDrop"
  >
    <!-- OUTLINE OVERLAY -->
    <div
      v-if="isDragActive"
      class="drag-overlay pointer-events-none absolute inset-0 rounded-lg border-2 border-indigo-400 z-20"
    ></div>

    <!-- CONTENT without Card wrapper -->
    <div class="flex flex-col h-full">
      <!-- hidden file input for click-to-select -->
      <input
        ref="fileInput"
        type="file"
        multiple
        class="hidden"
        @change="onFileSelect"
        :accept="filesExtensions"
      />

      <!-- Desktop UPLOAD ZONE -->
      <div
        v-if="!isTablet && !isMobile"
        class="mb-2 p-6 items-center justify-center border-2 border-dashed rounded-lg text-center transition-colors cursor-pointer relative mt-1"
        :class="{
          'border-indigo-500 bg-indigo-50': isDragActive,
          'border-gray-300 bg-white': !isDragActive,
          'opacity-60': uploadingBlocked,
        }"
        @click="onZoneClick"
        @dragenter.prevent="onDragEnter"
        @dragover.prevent="noop"
        @dragleave.prevent="onDragLeave"
        @drop.prevent.stop="onZoneDrop"
      >
        <!-- immediate uploading spinner -->
        <template v-if="uploading">
          <div class="flex items-center space-x-2 text-gray-500">
            <Loader2 class="animate-spin w-5 h-5" />
            <span>Uploading…</span>
          </div>
        </template>

        <!-- desktop drag and drop prompt -->
        <template v-else>
          <div class="flex w-full items-center justify-center">
            <Button variant="outline" :disabled="uploadingBlocked">
              <i class="dku-icon-file-16"></i>
              Select document(s)
            </Button>
            <span class="text-sm ml-2"> or drag and drop </span>
          </div>
        </template>
      </div>

      <!-- Mobile Upload Zone -->
      <div v-else class="mt-1">
        <template v-if="uploading">
          <div class="flex items-center space-x-2 text-gray-500">
            <Loader2 class="animate-spin w-5 h-5" />
            <span>Uploading…</span>
          </div>
        </template>

        <!-- mobile drag and drop prompt -->
        <template v-else>
          <Button variant="outline" :disabled="uploadingBlocked" @click="onZoneClick">
            <i class="dku-icon-file-16"></i>
            Select document(s)
          </Button>
        </template>
      </div>

      <!-- DOCUMENTS LIST -->
      <div class="flex-1 overflow-auto">
        <!-- Indexing Status Badge -->
        <div v-if="indexingBusy" class="mb-3 flex items-center justify-center">
          <Badge variant="secondary" class="animate-pulse">
            <Loader2 class="w-3 h-3 animate-spin mr-1.5" />
            <span v-if="addingCount && deletingCount">
              Processing: Adding {{ addingCount }}, Deleting {{ deletingCount }}
            </span>
            <span v-else-if="addingCount">
              Processing: Adding {{ addingCount }} document{{ addingCount > 1 ? 's' : '' }}
            </span>
            <span v-else-if="deletingCount">
              Processing: Deleting {{ deletingCount }} document{{ deletingCount > 1 ? 's' : '' }}
            </span>
            <span v-else> Processing documents... </span>
          </Badge>
        </div>

        <!-- delete all (only show when there are documents) -->
        <div v-if="docs.length > 0 && !indexingBusy" class="mb-2 flex justify-end items-center">
          <Button
            size="sm"
            variant="ghost"
            @click="confirmDeleteAll"
            class="text-xs"
            :disabled="indexingBusy"
          >
            <i class="dku-icon-trash-16 mr-1"></i>
            Delete All
          </Button>
        </div>

        <!-- File badges container -->
        <div v-if="docs.length" class="space-y-2">
          <!-- Desktop: Show all files -->
          <div v-if="!shouldShowAccordion" class="flex flex-wrap gap-2">
            <FileBadge
              v-for="doc in docs"
              :key="doc.name"
              :doc="doc"
              :select-mode="selectMode"
              :selected-docs="selectedDocs"
              :indexing-busy="indexingBusy"
              :indexing-status="indexing.status"
              @toggle-selection="toggleDocSelection"
              @delete="confirmDelete"
            />
          </div>

          <!-- Mobile: Show accordion when more than 5 files -->
          <div v-if="shouldShowAccordion" class="space-y-2">
            <!-- First 5 visible files -->
            <div class="flex flex-wrap gap-2">
              <FileBadge
                v-for="doc in visibleDocs"
                :key="doc.name"
                :doc="doc"
                :select-mode="selectMode"
                :selected-docs="selectedDocs"
                :indexing-busy="indexingBusy"
                :indexing-status="indexing.status"
                @toggle-selection="toggleDocSelection"
                @delete="confirmDelete"
              />
            </div>
            <!-- Accordion for remaining files -->
            <Accordion type="single" collapsible>
              <AccordionItem value="more-files" class="border-none">
                <AccordionTrigger class="py-2 px-0 text-sm !flex-none w-fit">
                  <span class="flex items-center"> View {{ hiddenDocs.length }} more </span>
                </AccordionTrigger>
                <AccordionContent class="pt-2">
                  <div class="flex flex-wrap gap-2">
                    <FileBadge
                      v-for="doc in hiddenDocs"
                      :key="doc.name"
                      :doc="doc"
                      :select-mode="selectMode"
                      :selected-docs="selectedDocs"
                      :indexing-busy="indexingBusy"
                      :indexing-status="indexing.status"
                      @toggle-selection="toggleDocSelection"
                      @delete="confirmDelete"
                    />
                  </div>
                </AccordionContent>
              </AccordionItem>
            </Accordion>
          </div>
        </div>
        <div class="flex justify-end mt-2" v-if="noActiveDocs.length">
          <Button size="lg" @click="launchIndexing" :disabled="uploadingBlocked">
            <i class="dku-icon-file-upload-16 mr-1"></i>
            <span>Process Document(s)</span>
          </Button>
        </div>
      </div>

      <!-- Floating action bar for bulk operations -->
      <Transition name="slide-up">
        <div
          v-if="selectMode && selectedDocs.size > 0"
          class="absolute bottom-4 left-1/2 transform -translate-x-1/2 bg-white border rounded-lg shadow-lg px-4 py-2 flex items-center gap-3"
        >
          <span class="text-sm text-gray-600"> {{ selectedDocs.size }} selected </span>
          <Button size="sm" variant="destructive" @click="confirmBulkDelete">
            Delete Selected
          </Button>
        </div>
      </Transition>
    </div>

    <!-- DELETE CONFIRMATION DIALOG -->
    <AlertDialog v-model:open="confirmOpen">
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle><i class="dku-icon-trash-16 mr-2"></i>Delete Document</AlertDialogTitle>
          <AlertDialogDescription>
            Delete <strong>{{ documentToDelete }}</strong
            >. This action cannot be undone
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Cancel</AlertDialogCancel>
          <AlertDialogAction @click="doDelete" class="bg-red-600 text-white hover:bg-red-700">
            Delete
          </AlertDialogAction>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>

    <!-- BULK DELETE CONFIRMATION DIALOG -->
    <AlertDialog v-model:open="showBulkDeleteConfirm">
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle
            ><i class="dku-icon-trash-16 mr-2"></i>Delete
            {{ selectedDocs.size }} Documents</AlertDialogTitle
          >
          <AlertDialogDescription>
            This will permanently delete {{ selectedDocs.size }} document{{
              selectedDocs.size > 1 ? 's' : ''
            }}. This action cannot be undone.
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Cancel</AlertDialogCancel>
          <AlertDialogAction class="bg-red-600 text-white hover:bg-red-700" @click="doBulkDelete">
            Delete all
          </AlertDialogAction>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>

    <!-- DELETE ALL CONFIRMATION DIALOG -->
    <AlertDialog v-model:open="showDeleteAllConfirm">
      <AlertDialogContent>
        <AlertDialogHeader>
          <AlertDialogTitle
            ><i class="dku-icon-trash-16 mr-2"></i>Delete All Documents</AlertDialogTitle
          >
          <AlertDialogDescription>
            This will permanently delete all {{ docs.length }} document{{
              docs.length > 1 ? 's' : ''
            }}. This action cannot be undone.
          </AlertDialogDescription>
        </AlertDialogHeader>
        <AlertDialogFooter>
          <AlertDialogCancel>Cancel</AlertDialogCancel>
          <AlertDialogAction class="bg-red-600 text-white hover:bg-red-700" @click="doDeleteAll">
            Delete all
          </AlertDialogAction>
        </AlertDialogFooter>
      </AlertDialogContent>
    </AlertDialog>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, watch, onMounted, onBeforeUnmount } from 'vue'
import { Loader2 } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import { Badge } from '@/components/ui/badge'
import {
  Accordion,
  AccordionContent,
  AccordionItem,
  AccordionTrigger,
} from '@/components/ui/accordion'
import {
  AlertDialog,
  AlertDialogContent,
  AlertDialogHeader,
  AlertDialogTitle,
  AlertDialogDescription,
  AlertDialogFooter,
  AlertDialogCancel,
  AlertDialogAction,
} from '@/components/ui/alert-dialog'
import { toast } from 'vue-sonner'
import { filesExtensions, type DocumentItem } from '@/types/document'
import { useIndexingStore, type JobBlob } from '@/store/indexingStore'
import { isIndexing } from '@/constants/indexing'
import { useSidebar } from '../ui/sidebar'
import FileBadge from './FileBadge.vue'
import { API } from '@/Api'
import { useAgentStore, type DocEntry } from '@/store/agentStore'
import { DOC_DELETE_FAILED, ERROR_409, UPLOAD_FAILED } from '@/constants/notifs'

// Props
const props = defineProps<{
  agentId: string
  agentName: string
  initialDocuments?: DocumentItem[]
  initialIndexing?: JobBlob
  uploadDisabled?: boolean
}>()

const agentStore = useAgentStore()

const { draft } = agentStore
watch(
  () => draft.documents,
  () => {
    filesToUpload.value = draft.documents?.filter((d) => d instanceof File) ?? []
  }
)
const docs = computed(() => draft.documents ?? [])
// State
const indexing = ref<JobBlob>({ status: '' })
const confirmOpen = ref(false)
const documentToDelete = ref<string>('')
const fileInput = ref<HTMLInputElement | null>(null)
const showDeleteAllConfirm = ref(false)

// Mobile detection
const { isTablet, isMobile } = useSidebar()

// Multi-select state
const selectMode = ref(false)
const selectedDocs = ref<Set<string>>(new Set())
const showBulkDeleteConfirm = ref(false)

// Drag & upload flags
const isDragActive = ref(false)
const dragCounter = ref(0)
const uploading = ref(false)

// Initialize from props
function initializeFromProps() {
  indexing.value = props.initialIndexing ? { ...props.initialIndexing } : { status: '' }
}
watch(
  () => props.initialIndexing,
  (newIndexing) => {
    if (newIndexing) {
      indexing.value = { ...newIndexing }
    }
  },
  { deep: true }
)

// Initialize on mount
onMounted(() => {
  initializeFromProps()
})

// Computed
const indexingBusy = computed(() => isIndexing(indexing.value?.status))

const uploadingBlocked = computed(
  () => Boolean(props.uploadDisabled) || indexingBusy.value || uploading.value
)

const addingCount = computed(
  () =>
    docs.value.filter((d: DocEntry) => !(d instanceof File) && !d.active && !d.deletePending).length
)

const deletingCount = computed(
  () => docs.value.filter((d: DocEntry) => !(d instanceof File) && d.deletePending).length
)

// Mobile accordion computed properties
const shouldShowAccordion = computed(() => docs.value.length > 5)
const visibleDocs = computed(() => {
  if (shouldShowAccordion.value) {
    return docs.value.slice(0, 5)
  }
  return docs.value
})
const hiddenDocs = computed(() => {
  if (shouldShowAccordion.value) {
    return docs.value.slice(5)
  }
  return []
})

// Helpers
function noop() {}

// Drag handlers
function onDragEnter() {
  if (uploadingBlocked.value) return
  dragCounter.value++
  isDragActive.value = true
}
function onDragLeave() {
  dragCounter.value--
  if (dragCounter.value <= 0) {
    dragCounter.value = 0
    isDragActive.value = false
  }
}
async function onZoneDrop(e: DragEvent) {
  e.preventDefault()
  dragCounter.value = 0
  isDragActive.value = false
  if (uploadingBlocked.value) return
  await upload(Array.from(e.dataTransfer?.files || []))
}

// Click & file-select
function onZoneClick() {
  if (!uploadingBlocked.value) fileInput.value?.click()
}
async function onFileSelect(e: Event) {
  if (uploadingBlocked.value) return
  dragCounter.value = 0
  isDragActive.value = false
  const inp = e.target as HTMLInputElement
  const files = Array.from(inp.files || [])
  inp.value = '' // reset so picking the same file fires "change" again
  await upload(files)
}

const filesToUpload = ref<any>(draft.documents?.filter((d) => d instanceof File) ?? [])
const noActiveDocs = computed(
  () =>
    draft.documents?.filter(
      (d: DocEntry) => !(d instanceof File) && !d.active && !d.deletePending
    ) ?? []
)
async function submitDocsDeletion(filenames: string[]) {
  try {
    const { data } = await API.deleteAgentDocuments(props.agentId, filenames)
    indexing.value = data.indexing
    useAgentStore().draft.documents = data.documents
    const idxStore = useIndexingStore()
    idxStore.track(props.agentId, data.indexing, props.agentName)
    window.dispatchEvent(
      new CustomEvent('docs-updated', {
        detail: { agentId: props.agentId, docs: docs.value, indexing: indexing.value },
      })
    )
    return true
  } catch (err: any) {
    toast.error(err.response?.status === 409 ? ERROR_409 : DOC_DELETE_FAILED)
    return false
  }
}
async function launchIndexing() {
  uploading.value = true
  try {
    const { data } = await API.indexAgentDocuments(props.agentId)
    indexing.value = data.indexing
    useAgentStore().draft.documents = data.documents
    // broadcast to store/sidebar
    const idxStore = useIndexingStore()
    idxStore.track(props.agentId, data.indexing, props.agentName)
    window.dispatchEvent(
      new CustomEvent('docs-updated', {
        detail: { agentId: props.agentId, docs: docs.value, indexing: indexing.value },
      })
    )
    const multiple = noActiveDocs.value.length > 1 ? 's' : ''
    toast.success(`${noActiveDocs.value.length} Document${multiple} queued for processing`)
  } catch (err: any) {
    toast.error(err.response?.status === 409 ? ERROR_409 : UPLOAD_FAILED)
  } finally {
    uploading.value = false
  }
}
// Upload
async function upload(files: File[]) {
  if (!files.length) return

  const allowedExtensions = filesExtensions.split(',').map((ext) => ext.trim())
  const validFiles = []
  const invalidFiles = []

  for (const file of files) {
    const extension = ('.' + file.name.split('.').pop()?.toLowerCase()) as string
    if (allowedExtensions.includes(extension)) {
      validFiles.push(file)
    } else {
      invalidFiles.push(file)
    }
  }

  if (invalidFiles.length > 0) {
    const rejectedExtensions = [
      ...new Set(invalidFiles.map((f) => '.' + f.name.split('.').pop()?.toLowerCase())),
    ]
    toast.warning(
      `${
        invalidFiles.length
      } file(s) were ignored due to unsupported file type(s): ${rejectedExtensions.join(
        ', '
      )}. Supported types: ${allowedExtensions.join(', ')}`
    )
  }

  if (validFiles.length === 0) {
    return
  }

  const existing = new Set(docs.value.map((d) => (typeof d === 'string' ? d : d.name)))
  const toSave = validFiles.filter((f) => !existing.has(f.name))

  if (toSave.length === 0) {
    // All valid files were duplicates. Only show toast if no invalid files were found.
    if (invalidFiles.length === 0) {
      toast.info('Selected document(s) already uploaded for this agent')
    }
    return
  }
  try {
    filesToUpload.value.push(...toSave)
    const { data } = await API.uploadAgentDocument(props.agentId, filesToUpload.value)
    filesToUpload.value = []
    useAgentStore().draft.documents = data.documents
    window.dispatchEvent(
      new CustomEvent('docs-updated', {
        detail: { agentId: props.agentId, docs: docs.value, indexing: 'pending' },
      })
    )
    toast.success(`${toSave.length} Document${toSave.length > 1 ? 's' : ''} uploaded successfully`)
  } catch (err: any) {
    toast.error(err.response?.status === 409 ? ERROR_409 : UPLOAD_FAILED)
  } finally {
    uploading.value = false
  }
}

function toggleDocSelection(docName: string) {
  if (selectedDocs.value.has(docName)) {
    selectedDocs.value.delete(docName)
  } else {
    selectedDocs.value.add(docName)
  }
  // Force reactivity
  selectedDocs.value = new Set(selectedDocs.value)
}

function confirmBulkDelete() {
  if (selectedDocs.value.size === 0) return
  showBulkDeleteConfirm.value = true
}

async function doBulkDelete() {
  showBulkDeleteConfirm.value = false
  const filenames = Array.from(selectedDocs.value) as string[]

  await submitDocsDeletion(filenames)
}

// Delete single document
function confirmDeleteAll() {
  showDeleteAllConfirm.value = true
}

function confirmDelete(docName: string) {
  documentToDelete.value = docName
  confirmOpen.value = true
}

async function doDelete() {
  confirmOpen.value = false
  const filenames = [documentToDelete.value]
  await submitDocsDeletion(filenames)
}

async function doDeleteAll() {
  showDeleteAllConfirm.value = false
  const filenames = docs.value.map((doc) => (typeof doc === 'string' ? doc : doc.name))
  await submitDocsDeletion(filenames)
}

// Sync across components
function handleDocsUpdated(e: any) {
  const d = e.detail
  if (!d || d.agentId !== props.agentId) return
  useAgentStore().draft.documents = d.docs
  useAgentStore().draft.indexing = d.indexing
  indexing.value = d.indexing
  window.dispatchEvent(
    new CustomEvent('agent-saved', {
      detail: {
        id: props.agentId,
        name: props.agentName,
        status: 'draft',
        hasUnpublishedChanges: true,
        indexing: indexing.value,
      },
    })
  )
}

onMounted(() => window.addEventListener('docs-updated', handleDocsUpdated))
onBeforeUnmount(() => window.removeEventListener('docs-updated', handleDocsUpdated))
</script>

<style scoped>
/* Slide up transition for floating action bar */
.slide-up-enter-active,
.slide-up-leave-active {
  transition: all 0.3s ease;
}

.slide-up-enter-from {
  opacity: 0;
  transform: translate(-50%, 20px);
}

.slide-up-leave-to {
  opacity: 0;
  transform: translate(-50%, 20px);
}
</style>
