<script setup>
import { inject, ref } from 'vue';

const props = defineProps({
    modelValue: {
        type: String,
        default: '',
    },
    uploadUrl: {
        type: String,
        default: null,
    },
    label: {
        type: String,
        default: '',
    },
});

const emit = defineEmits(['update:modelValue']);

const isDragOver = ref(false);
const isUploading = ref(false);
const error = ref(null);
const fileInputRef = ref(null);
const localPreview = ref(null);

// Plugs into the parent editor's pending-upload counter so the form submit
// can be blocked while this upload is in flight.
const pendingUploads = inject('editorPendingUploads', null);

const uploadFile = async (file) => {
    if (!file) {
        return;
    }

    if (!file.type.startsWith('image/')) {
        error.value = 'Only image files are accepted.';
        return;
    }

    // Emit blob URL immediately so the right-side preview updates at once
    if (localPreview.value) {
        URL.revokeObjectURL(localPreview.value);
    }
    localPreview.value = URL.createObjectURL(file);
    error.value = null;
    emit('update:modelValue', localPreview.value);

    if (!props.uploadUrl) {
        // No upload endpoint — blob URL stays as the value
        return;
    }

    isUploading.value = true;
    if (pendingUploads) pendingUploads.value++;

    try {
        const csrfToken = document.querySelector('meta[name="csrf-token"]')?.getAttribute('content') ?? '';
        const formData = new FormData();
        formData.append('image', file);

        const response = await fetch(props.uploadUrl, {
            method: 'POST',
            headers: { 'X-CSRF-TOKEN': csrfToken },
            body: formData,
        });

        if (!response.ok) {
            throw new Error('Upload failed');
        }

        const data = await response.json();
        // Replace blob URL with the permanent server URL
        URL.revokeObjectURL(localPreview.value);
        localPreview.value = null;
        emit('update:modelValue', data.url);
    } catch {
        error.value = 'Upload failed. Please try again.';
        URL.revokeObjectURL(localPreview.value);
        localPreview.value = null;
        emit('update:modelValue', '');
    } finally {
        isUploading.value = false;
        if (pendingUploads) pendingUploads.value--;
    }
};

const onDragOver = (event) => {
    event.preventDefault();
    isDragOver.value = true;
};

const onDragLeave = () => {
    isDragOver.value = false;
};

const onDrop = (event) => {
    event.preventDefault();
    isDragOver.value = false;
    const file = event.dataTransfer?.files?.[0];

    if (file) {
        uploadFile(file);
    }
};

const openPicker = () => {
    fileInputRef.value.value = '';
    fileInputRef.value.click();
};

const onFileSelected = (event) => {
    const file = event.target.files[0];

    if (file) {
        uploadFile(file);
    }
};

const clearImage = (event) => {
    event.stopPropagation();
    if (localPreview.value) {
        URL.revokeObjectURL(localPreview.value);
        localPreview.value = null;
    }
    emit('update:modelValue', '');
};
</script>

<template>
    <div
        class="image-drop-zone"
        :class="{
            'image-drop-zone--over': isDragOver,
            'image-drop-zone--uploading': isUploading,
            'image-drop-zone--filled': !!(localPreview || modelValue),
        }"
        @dragover="onDragOver"
        @dragleave="onDragLeave"
        @drop="onDrop"
        @click="openPicker"
    >
        <template v-if="localPreview || modelValue">
            <img :src="localPreview || modelValue" class="image-drop-zone__preview" :class="{ 'image-drop-zone__preview--uploading': isUploading }" alt="">
            <div class="image-drop-zone__overlay">
                <span class="image-drop-zone__overlay-text">{{ isUploading ? 'Uploading…' : 'Drop or click to replace' }}</span>
                <button v-if="!isUploading" type="button" class="image-drop-zone__clear" @click="clearImage" title="Remove image">✕</button>
            </div>
        </template>

        <template v-else>
            <div class="image-drop-zone__empty">
                <span class="image-drop-zone__icon">{{ isUploading ? '⏳' : '🖼' }}</span>
                <span class="image-drop-zone__hint">{{ isUploading ? 'Uploading…' : (uploadUrl ? 'Drop image or click to upload' : 'Drop image here') }}</span>
                <span v-if="label" class="image-drop-zone__label">{{ label }}</span>
            </div>
        </template>
    </div>

    <p v-if="error" class="image-drop-zone__error">{{ error }}</p>

    <input ref="fileInputRef" type="file" accept="image/*" class="image-drop-zone__input" @change="onFileSelected">
</template>

<style scoped>
.image-drop-zone {
    border: 2px dashed rgba(15, 23, 42, 0.15);
    border-radius: 0.75rem;
    cursor: pointer;
    overflow: hidden;
    position: relative;
    transition: border-color 0.15s, background 0.15s;
    user-select: none;
}

.image-drop-zone--over {
    background: #f0f9ff;
    border-color: rgba(14, 116, 144, 0.6);
}

.image-drop-zone--uploading {
    pointer-events: none;
}

.image-drop-zone--filled {
    border-style: solid;
    border-color: rgba(15, 23, 42, 0.12);
}

/* Empty state */
.image-drop-zone__empty {
    align-items: center;
    display: flex;
    flex-direction: column;
    gap: 0.35rem;
    justify-content: center;
    min-height: 6rem;
    padding: 1rem;
}

.image-drop-zone__icon {
    font-size: 1.6rem;
    line-height: 1;
}

.image-drop-zone__hint {
    color: #64748b;
    font-size: 0.8rem;
    font-weight: 600;
    text-align: center;
}

.image-drop-zone__label {
    color: #94a3b8;
    font-size: 0.72rem;
    text-align: center;
}

/* Filled state */
.image-drop-zone__preview {
    display: block;
    height: 9rem;
    object-fit: cover;
    width: 100%;
}

.image-drop-zone__preview--uploading {
    opacity: 0.5;
}

.image-drop-zone__overlay {
    align-items: center;
    background: rgba(15, 23, 42, 0.5);
    bottom: 0;
    display: flex;
    justify-content: space-between;
    left: 0;
    opacity: 0;
    padding: 0.4rem 0.6rem;
    position: absolute;
    right: 0;
    transition: opacity 0.15s;
}

.image-drop-zone:hover .image-drop-zone__overlay {
    opacity: 1;
}

.image-drop-zone__overlay-text {
    color: #fff;
    font-size: 0.75rem;
    font-weight: 600;
}

.image-drop-zone__clear {
    background: rgba(255, 255, 255, 0.15);
    border: 0;
    border-radius: 50%;
    color: #fff;
    cursor: pointer;
    font-size: 0.75rem;
    height: 1.4rem;
    line-height: 1;
    padding: 0;
    width: 1.4rem;
}

.image-drop-zone__clear:hover {
    background: rgba(239, 68, 68, 0.75);
}

.image-drop-zone__input {
    display: none;
}

.image-drop-zone__error {
    color: #b91c1c;
    font-size: 0.8rem;
    margin: 0.25rem 0 0;
}
</style>
