<template>
  <div class="image-upload">
    <div
      class="upload-area border-2 border-dashed rounded-lg p-6 text-center transition-colors"
      :class="{
        'border-primary': isDragging,
        'opacity-50 cursor-not-allowed': disabled,
        'cursor-pointer hover:border-primary': !disabled && images.length > 0
      }"
      @click="!disabled && images.length > 0 && triggerFileInput()"
      @drop.prevent.stop="handleDrop"
      @dragover.prevent="isDragging = true"
      @dragleave.prevent="isDragging = false"
    >
      <!-- Gallery file input -->
      <input
        ref="galleryInput"
        type="file"
        @change.stop.prevent="handleFileSelect"
        accept="image/*"
        :multiple="multiple"
        :disabled="disabled"
        tabindex="-1"
        hidden
      />

      <!-- Camera file input - no multiple attribute for direct camera access -->
      <input
        ref="cameraInput"
        type="file"
        @change.stop.prevent="handleFileSelect"
        accept="image/*"
        capture="environment"
        :disabled="disabled"
        tabindex="-1"
        hidden
      />

      <div v-if="!uploading && images.length === 0" class="upload-placeholder">
        <div class="flex justify-center gap-4 mb-6">
          <!-- Gallery Button -->
          <Button
            @click.stop="triggerGalleryInput"
            type="button"
            variant="outline"
            class="flex flex-col items-center gap-2 h-auto py-4 px-6"
            :disabled="disabled"
          >
            <Image class="w-6 h-6" />
            <span class="text-sm">Gallery</span>
          </Button>

          <!-- Camera Button -->
          <Button
            v-if="allowCamera"
            @click.stop="triggerCameraInput"
            type="button"
            variant="outline"
            class="flex flex-col items-center gap-2 h-auto py-4 px-6"
            :disabled="disabled"
          >
            <Camera class="w-6 h-6" />
            <span class="text-sm">Camera</span>
          </Button>
        </div>

        <p class="text-lg font-medium mb-2">
          {{ placeholder || 'Choose photos from gallery or take with camera' }}
        </p>
        <p class="text-sm text-muted-foreground">
          Supports PNG, JPG, WEBP, AVIF • Max {{ maxSizeMB }}MB per file
        </p>
        <p class="text-xs text-muted-foreground mt-2">
          Or drag images here to upload
        </p>
      </div>

      <div v-if="uploading" class="uploading flex flex-col items-center gap-3">
        <Loader2 class="w-8 h-8 animate-spin" />
        <p class="text-sm">Uploading {{ uploadingCount }} image{{ uploadingCount > 1 ? 's' : '' }}...</p>
      </div>
    </div>

    <div v-if="images.length > 0" class="mt-4">
      <!-- Image Grid -->
      <div class="image-grid grid grid-cols-2 sm:grid-cols-3 md:grid-cols-4 gap-4">
        <div
          v-for="image in images"
          :key="image.alias"
          class="image-item relative rounded-lg overflow-hidden border-2"
          :class="{ 'border-primary': image.isPrimary }"
        >
          <img
            :src="getImageThumbnailUrl(image)"
            :alt="image.alias"
            class="w-full h-32 object-cover"
          />
          <div class="image-actions absolute top-1 right-1 flex gap-1">
            <Button
              v-if="showPrimaryButton && images.length > 1"
              @click.stop.prevent="setAsPrimary(image)"
              type="button"
              size="sm"
              variant="secondary"
              class="h-7 px-2 text-xs"
              :class="{ 'bg-primary text-primary-foreground': image.isPrimary }"
            >
              {{ image.isPrimary ? 'Primary' : 'Set Primary' }}
            </Button>
            <Button
              @click.stop.prevent="removeImage(image)"
              type="button"
              size="sm"
              variant="destructive"
              class="h-7 w-7 p-0"
              :disabled="disabled"
            >
              <X class="h-4 w-4" />
            </Button>
          </div>
        </div>
      </div>

      <!-- Add More Images Buttons -->
      <div v-if="!maxFiles || images.length < maxFiles" class="flex justify-center gap-3 mt-4 pt-4 border-t border-dashed">
        <Button
          @click.stop="triggerGalleryInput"
          type="button"
          variant="outline"
          size="sm"
          :disabled="disabled"
        >
          <Image class="w-4 h-4 mr-2" />
          Add from Gallery
        </Button>
        <Button
          v-if="allowCamera"
          @click.stop="triggerCameraInput"
          type="button"
          variant="outline"
          size="sm"
          :disabled="disabled"
        >
          <Camera class="w-4 h-4 mr-2" />
          Take Photo
        </Button>
      </div>
    </div>

    <Alert v-if="error" variant="destructive" class="mt-4">
      <AlertCircle class="h-4 w-4" />
      <AlertDescription>{{ error }}</AlertDescription>
    </Alert>
  </div>
</template>

<script setup lang="ts">
import { ref, computed, defineEmits, defineProps, nextTick } from 'vue'
import { Camera, X, Loader2, AlertCircle, Image } from 'lucide-vue-next'
import { Button } from '@/components/ui/button'
import { Alert, AlertDescription } from '@/components/ui/alert'
import { injectService, SERVICE_TOKENS } from '@/core/di-container'
import type { ImageUploadService, UploadedImage } from '../services/ImageUploadService'

interface ImageWithMetadata extends UploadedImage {
  isPrimary: boolean
}

const props = defineProps<{
  modelValue?: ImageWithMetadata[]
  multiple?: boolean
  maxFiles?: number
  maxSizeMB?: number
  showPrimaryButton?: boolean
  disabled?: boolean
  placeholder?: string
  allowCamera?: boolean
}>()

const emit = defineEmits<{
  'update:modelValue': [images: ImageWithMetadata[]]
}>()

// Inject the image upload service
const imageService = injectService<ImageUploadService>(SERVICE_TOKENS.IMAGE_UPLOAD_SERVICE)

// Component state
const galleryInput = ref<HTMLInputElement | null>(null)
const cameraInput = ref<HTMLInputElement | null>(null)
const uploading = ref(false)
const uploadingCount = ref(0)
const error = ref('')
const isDragging = ref(false)

// Use v-model or internal state
const images = computed({
  get: () => props.modelValue || [],
  set: (value) => {
    emit('update:modelValue', value)
  }
})

const maxSizeMB = computed(() => props.maxSizeMB || imageService.getStatus().maxFileSizeMB)

// Note: Camera capture is now handled by separate input elements

// Helper function to get thumbnail URL that works for both uploaded images and existing URLs
const getImageThumbnailUrl = (image: ImageWithMetadata): string => {
  // Now we always have file IDs as aliases, so we can always use the service
  return imageService.getThumbnailUrl(image.alias, 200)
}

/**
 * DEFENSIVE FORM SUBMISSION PREVENTION
 *
 * Mobile browsers (especially on Android) can unpredictably trigger form submissions
 * when file inputs are activated, particularly with camera capture. This causes
 * intermittent page refreshes that lose form data.
 *
 * Our multi-layer defense strategy:
 * 1. Mutex lock (inputInUse) prevents simultaneous input triggers
 * 2. Window-level submit event capture during critical operations
 * 3. Form-level submit blocking during async operations
 * 4. Vue event modifiers (.stop.prevent) on all user interactions
 * 5. Explicit event prevention in handlers as backup
 *
 * This defensive approach is necessary because the issue is intermittent
 * and may be caused by browser quirks, timing issues, or mobile-specific behaviors.
 */

// Track which input is being triggered to prevent conflicts between gallery and camera
const inputInUse = ref<'gallery' | 'camera' | null>(null)

const triggerGalleryInput = () => {
  if (!props.disabled && galleryInput.value && inputInUse.value === null) {
    inputInUse.value = 'gallery'

    // DEFENSIVE: Add temporary form submit blocker at window level
    // This catches any form submission attempts during the critical moment
    // when the file input is being triggered
    const submitBlocker = (e: Event) => {
      e.preventDefault()
      e.stopImmediatePropagation()
      return false
    }
    window.addEventListener('submit', submitBlocker, true)

    galleryInput.value.click()

    // Reset after a delay and remove blocker
    setTimeout(() => {
      inputInUse.value = null
      window.removeEventListener('submit', submitBlocker, true)
    }, 500)
  }
}

const triggerCameraInput = () => {
  if (!props.disabled && cameraInput.value && inputInUse.value === null) {
    inputInUse.value = 'camera'

    // DEFENSIVE: Camera inputs are especially prone to triggering form submissions
    // on mobile browsers. This window-level blocker prevents any submission
    // during the critical camera activation period
    const submitBlocker = (e: Event) => {
      e.preventDefault()
      e.stopImmediatePropagation()
      return false
    }
    window.addEventListener('submit', submitBlocker, true)

    cameraInput.value.click()

    // Reset after a delay and remove blocker
    setTimeout(() => {
      inputInUse.value = null
      window.removeEventListener('submit', submitBlocker, true)
    }, 500)
  }
}

// Note: Click event handling is done via Vue modifiers (@click.stop) in template

// Legacy method for drag & drop compatibility
const triggerFileInput = () => {
  // Default to gallery for drag & drop
  triggerGalleryInput()
}

const handleFileSelect = (event: Event) => {
  const target = event.target as HTMLInputElement
  const files = Array.from(target.files || [])

  // DEFENSIVE: Clear the input immediately to prevent any lingering state
  // that might trigger additional events
  const filesCopy = [...files]
  target.value = ''

  // DEFENSIVE: Add extra protection against form submission during file processing
  // The console.warn helps debug intermittent issues by showing when submissions are blocked
  const submitGuard = (e: Event) => {
    e.preventDefault()
    e.stopImmediatePropagation()
    console.warn('Form submission blocked during file upload')
    return false
  }

  // DEFENSIVE: Block form submissions at the window level during processing
  // This catches submissions that might bypass other preventions
  window.addEventListener('submit', submitGuard, true)

  // Process files after clearing input
  if (filesCopy.length > 0) {
    // DEFENSIVE: Use nextTick to ensure DOM updates are processed before upload
    // This helps prevent timing-related submission issues
    nextTick(() => {
      uploadFiles(filesCopy).finally(() => {
        // Remove guard after upload completes (important for cleanup)
        window.removeEventListener('submit', submitGuard, true)
      })
    })
  } else {
    window.removeEventListener('submit', submitGuard, true)
  }
}

const handleDrop = (event: DragEvent) => {
  isDragging.value = false

  if (props.disabled) return

  const files = Array.from(event.dataTransfer?.files || [])
  const imageFiles = files.filter(file => file.type.startsWith('image/'))
  uploadFiles(imageFiles)
}

const uploadFiles = async (files: File[]) => {
  if (files.length === 0) return

  // Check max files limit
  if (props.maxFiles && images.value.length + files.length > props.maxFiles) {
    error.value = `Maximum ${props.maxFiles} images allowed`
    return
  }

  uploading.value = true
  uploadingCount.value = files.length
  error.value = ''

  // DEFENSIVE: Multiple layers of form submission prevention during upload
  // This is our most comprehensive protection, active during the actual upload process
  const forms = document.querySelectorAll('form')
  const originalHandlers: Array<{ form: HTMLFormElement; onsubmit: any }> = []

  forms.forEach(form => {
    // Store original handler for restoration
    originalHandlers.push({ form, onsubmit: form.onsubmit })

    // DEFENSIVE LAYER 1: Override onsubmit handler directly
    form.onsubmit = (e) => {
      e.preventDefault()
      e.stopPropagation()
      e.stopImmediatePropagation()
      return false  // Belt and suspenders - return false as extra prevention
    }

    // DEFENSIVE LAYER 2: Add capturing event listener as backup
    // This catches submissions even if onsubmit is somehow bypassed
    form.addEventListener('submit', preventSubmit, true)
  })

  // Helper function for preventing submission with all available methods
  function preventSubmit(e: Event) {
    e.preventDefault()
    e.stopPropagation()
    e.stopImmediatePropagation()
    return false
  }

  try {
    const uploadOptions = {
      maxSizeMB: maxSizeMB.value
    }

    // Upload files with better error handling
    const { results: uploadResults, errors: uploadErrors } = await imageService.uploadImages(files, uploadOptions)

    // Process successful uploads
    const newImages: ImageWithMetadata[] = uploadResults.map((result, index) => ({
      ...result,
      isPrimary: images.value.length === 0 && index === 0 // First image becomes primary
    }))

    if (newImages.length > 0) {
      images.value = [...images.value, ...newImages]
    }

    // Handle upload errors with user-friendly messages
    if (uploadErrors.length > 0) {
      if (uploadErrors.length === files.length) {
        // All uploads failed
        error.value = uploadErrors.length === 1
          ? uploadErrors[0].error
          : `All ${uploadErrors.length} images failed to upload`
      } else {
        // Partial failure
        const failedFiles = uploadErrors.map(e => e.file).join(', ')
        error.value = `Some images failed to upload: ${failedFiles}`
      }
    }

    // Clear errors on successful upload (if no upload errors occurred)
    if (newImages.length > 0 && uploadErrors.length === 0) {
      error.value = ''
    }

  } catch (err) {
    error.value = err instanceof Error ? err.message : 'Failed to upload images'
    console.error('Upload error:', err)
  } finally {
    uploading.value = false
    uploadingCount.value = 0

    // DEFENSIVE CLEANUP: Restore all original form submission handlers
    // Critical to restore normal form behavior after upload completes
    originalHandlers.forEach(({ form, onsubmit }) => {
      form.onsubmit = onsubmit
      form.removeEventListener('submit', preventSubmit, true)
    })
  }
}

const setAsPrimary = (selectedImage: ImageWithMetadata) => {
  images.value = images.value.map(img => ({
    ...img,
    isPrimary: img.alias === selectedImage.alias
  }))
}

const removeImage = async (imageToRemove: ImageWithMetadata) => {
  if (props.disabled) return

  try {
    // Only try to delete from pict-rs if we have a delete token (newly uploaded images)
    if (imageToRemove.delete_token) {
      await imageService.deleteImage(imageToRemove.delete_token, imageToRemove.alias)
    }

    const newImages = images.value.filter(img => img.alias !== imageToRemove.alias)

    // If removed image was primary, make first image primary
    if (imageToRemove.isPrimary && newImages.length > 0) {
      newImages[0].isPrimary = true
    }

    images.value = newImages

    // Clear any errors on successful removal
    if (error.value) {
      error.value = ''
    }

  } catch (err) {
    error.value = err instanceof Error ? err.message : 'Failed to delete image'
    console.error('Delete error:', err)
  }
}

// Expose utility methods for parent components
defineExpose({
  uploadFiles,
  clearImages: () => { images.value = [] },
  getPrimaryImage: () => images.value.find(img => img.isPrimary),
  getAllImages: () => images.value
})
</script>