<template>
  <Teleport to="body">
    <Transition name="fade">
      <div
        v-if="isVisible"
        class="drag-drop-overlay"
        @dragover.prevent
        @dragleave.prevent="onDragLeave"
        @drop.prevent="onDrop"
      >
        <div class="overlay-content">
          <i class="pi pi-cloud-upload overlay-icon"></i>
          <p class="overlay-text">
            Eliberează pentru a încărca {{ fileCount }} {{ fileCount === 1 ? 'fișier' : 'fișiere' }}
          </p>
          <p class="overlay-hint">PDF, PNG, JPG (max 10MB per fișier)</p>
        </div>
      </div>
    </Transition>
  </Teleport>
</template>

<script setup>
import { ref, onMounted, onUnmounted, computed } from 'vue'
import { useToast } from 'primevue/usetoast'
import api from '@data-entry/services/api'

const emit = defineEmits(['upload-started', 'upload-complete', 'upload-error'])

const toast = useToast()

// Drag state
const dragCounter = ref(0)
const fileCount = ref(0)

// Validation constants (matching backend)
const MAX_FILE_SIZE_MB = 10
const MAX_FILE_SIZE_BYTES = MAX_FILE_SIZE_MB * 1024 * 1024
const ALLOWED_MIME_TYPES = ['application/pdf', 'image/png', 'image/jpeg']

// Computed visibility based on drag counter
const isVisible = computed(() => dragCounter.value > 0)

/**
 * Check if a drag event contains files.
 * We check types array for 'Files' or 'application/x-moz-file' (Firefox).
 */
const hasFiles = (event) => {
  if (!event.dataTransfer) return false
  const types = event.dataTransfer.types
  return types && (types.includes('Files') || types.includes('application/x-moz-file'))
}

/**
 * Handle dragenter on window.
 * Only activate overlay if dragging files (not text selection, etc.)
 */
const onWindowDragEnter = (event) => {
  if (!hasFiles(event)) return

  dragCounter.value++

  // Try to get file count from items (not always available during drag)
  if (event.dataTransfer?.items) {
    fileCount.value = event.dataTransfer.items.length
  } else {
    fileCount.value = 0 // Will show "fișiere" (plural)
  }
}

/**
 * Handle dragover on window.
 * Prevent default to allow drop.
 */
const onWindowDragOver = (event) => {
  if (!hasFiles(event)) return
  event.preventDefault()
}

/**
 * Handle dragleave on window.
 * Decrement counter; hide overlay when 0.
 */
const onWindowDragLeave = () => {
  dragCounter.value = Math.max(0, dragCounter.value - 1)
}

/**
 * Handle dragleave on overlay itself (user drags outside window).
 */
const onDragLeave = (event) => {
  // Only hide if leaving to outside the document
  if (!event.relatedTarget || event.relatedTarget.nodeName === 'HTML') {
    dragCounter.value = 0
    fileCount.value = 0
  }
}

/**
 * Handle drop on overlay.
 */
const onDrop = async (event) => {
  // Reset drag state immediately
  dragCounter.value = 0
  fileCount.value = 0

  const files = event.dataTransfer?.files
  if (!files || files.length === 0) return

  await handleFiles(Array.from(files))
}

/**
 * Handle drop on window (catch drops that miss overlay).
 */
const onWindowDrop = async (event) => {
  // Only handle if overlay was visible
  if (dragCounter.value === 0) return

  event.preventDefault()
  dragCounter.value = 0
  fileCount.value = 0

  const files = event.dataTransfer?.files
  if (!files || files.length === 0) return

  await handleFiles(Array.from(files))
}

/**
 * Clone files to memory immediately to avoid SnapshotState invalidation on mobile.
 * On Chrome Android/iOS, accessing File properties after the event handler returns
 * can fail because the browser invalidates the File object reference.
 * See: https://issues.chromium.org/40703873
 *
 * CRITICAL: Clone FIRST, then access properties from the cloned file.
 */
const cloneFilesToMemory = async (files) => {
  const clonedFiles = []

  for (const file of files) {
    try {
      // Read file content into memory IMMEDIATELY, before any property access
      const arrayBuffer = await file.arrayBuffer()
      const clonedFile = new File([arrayBuffer], file.name, {
        type: file.type,
        lastModified: file.lastModified
      })
      clonedFiles.push(clonedFile)
    } catch (e) {
      console.warn('[DragDropOverlay] File clone failed:', e)
      // On clone failure, try to use original (will fail on mobile but works on desktop)
      clonedFiles.push(file)
    }
  }

  return clonedFiles
}

/**
 * Validate and upload files via bulk upload API.
 */
const handleFiles = async (files) => {
  // CRITICAL FIX for US-037: Clone files to memory FIRST
  // This prevents page reload on mobile when accessing file properties
  const clonedFiles = await cloneFilesToMemory(files)

  const validFiles = []
  const invalidFiles = []

  // Validate each CLONED file (safe to access properties now)
  for (const file of clonedFiles) {
    // Check MIME type
    if (!ALLOWED_MIME_TYPES.includes(file.type)) {
      invalidFiles.push({
        name: file.name,
        reason: `Tip invalid (${file.type || 'necunoscut'})`
      })
      continue
    }

    // Check file size
    if (file.size > MAX_FILE_SIZE_BYTES) {
      invalidFiles.push({
        name: file.name,
        reason: `Prea mare (${formatFileSize(file.size)} > ${MAX_FILE_SIZE_MB}MB)`
      })
      continue
    }

    // File already cloned, just add to valid list
    validFiles.push(file)
  }

  // Show warning toast for invalid files
  if (invalidFiles.length > 0) {
    const fileList = invalidFiles
      .slice(0, 3)
      .map(f => `• ${f.name}: ${f.reason}`)
      .join('\n')

    const moreCount = invalidFiles.length - 3
    const detail = moreCount > 0
      ? `${fileList}\n...și încă ${moreCount} fișiere`
      : fileList

    toast.add({
      severity: 'warn',
      summary: `${invalidFiles.length} fișier${invalidFiles.length > 1 ? 'e' : ''} ignorat${invalidFiles.length > 1 ? 'e' : ''}`,
      detail,
      life: 5000
    })
  }

  // If no valid files, we're done
  if (validFiles.length === 0) {
    return
  }

  // Upload via bulk API
  try {
    emit('upload-started', validFiles.length)

    const formData = new FormData()
    validFiles.forEach(file => {
      formData.append('files', file)
    })

    const response = await api.post('/bulk/upload', formData)

    // Show success toast
    const data = response.data
    let message = `${data.processed_files || data.total_files} fișier${(data.processed_files || data.total_files) > 1 ? 'e' : ''} încărcat${(data.processed_files || data.total_files) > 1 ? 'e' : ''}`

    // Add duplicate info if present
    if (data.duplicate_files && data.duplicate_files > 0) {
      message += `, ${data.duplicate_files} duplicate ignorate`
    }

    toast.add({
      severity: 'success',
      summary: 'Upload reușit',
      detail: message,
      life: 4000
    })

    // US-017: Include filenames mapped to job_ids for instant table display
    // Create job info array by pairing job_ids with original filenames
    // Note: Backend returns job_ids in the same order as files were submitted
    const jobs = data.job_ids.map((jobId, index) => ({
      job_id: jobId,
      filename: validFiles[index]?.name || `File ${index + 1}`
    }))

    emit('upload-complete', {
      batchId: data.batch_id != null ? String(data.batch_id) : null,
      jobIds: data.job_ids,
      jobs: jobs, // US-017: Add job info with filenames
      totalFiles: data.total_files,
      processedFiles: data.processed_files,
      duplicates: data.duplicates
    })

  } catch (error) {
    console.error('[DragDropOverlay] Upload failed:', error)

    let errorMessage = 'Eroare la încărcare'

    if (error.response?.data?.detail) {
      const detail = error.response.data.detail
      if (typeof detail === 'string') {
        errorMessage = detail
      } else if (detail.message) {
        errorMessage = detail.message
        // Show duplicate info if all files were duplicates
        if (detail.duplicates && detail.duplicates.length > 0) {
          const dupList = detail.duplicates
            .slice(0, 3)
            .map(d => `• ${d.filename}: ${d.message}`)
            .join('\n')
          errorMessage += '\n' + dupList
        }
      }
    }

    toast.add({
      severity: 'error',
      summary: 'Upload eșuat',
      detail: errorMessage,
      life: 6000
    })

    emit('upload-error', error)
  }
}

/**
 * Format file size for display.
 */
const formatFileSize = (bytes) => {
  if (bytes < 1024) return bytes + ' B'
  if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB'
  return (bytes / (1024 * 1024)).toFixed(1) + ' MB'
}

// Event listeners setup/cleanup
onMounted(() => {
  window.addEventListener('dragenter', onWindowDragEnter)
  window.addEventListener('dragover', onWindowDragOver)
  window.addEventListener('dragleave', onWindowDragLeave)
  window.addEventListener('drop', onWindowDrop)
})

onUnmounted(() => {
  window.removeEventListener('dragenter', onWindowDragEnter)
  window.removeEventListener('dragover', onWindowDragOver)
  window.removeEventListener('dragleave', onWindowDragLeave)
  window.removeEventListener('drop', onWindowDrop)
})

// Expose handleFiles so parent can call it programmatically (e.g., from a button click)
defineExpose({
  handleFiles
})
</script>

<style scoped>
.drag-drop-overlay {
  position: fixed;
  inset: 0;
  z-index: 9999;
  background: rgba(0, 0, 0, 0.7);
  display: flex;
  align-items: center;
  justify-content: center;
  backdrop-filter: blur(4px);
}

.overlay-content {
  display: flex;
  flex-direction: column;
  align-items: center;
  gap: var(--space-md);
  padding: var(--space-xl);
  background: var(--surface-card);
  border-radius: var(--radius-lg);
  border: 3px dashed var(--primary-500);
  box-shadow: var(--shadow-xl);
  text-align: center;
  max-width: 400px;
}

.overlay-icon {
  font-size: 4rem;
  color: var(--primary-500);
  animation: pulse 1.5s ease-in-out infinite;
}

@keyframes pulse {
  0%, 100% {
    transform: scale(1);
    opacity: 1;
  }
  50% {
    transform: scale(1.1);
    opacity: 0.8;
  }
}

.overlay-text {
  font-size: var(--text-xl);
  font-weight: var(--font-semibold);
  color: var(--text-color);
  margin: 0;
}

.overlay-hint {
  font-size: var(--text-sm);
  color: var(--text-color-secondary);
  margin: 0;
}

/* Fade transition */
.fade-enter-active,
.fade-leave-active {
  transition: opacity var(--transition-fast);
}

.fade-enter-from,
.fade-leave-to {
  opacity: 0;
}
</style>
