<script setup lang="ts">
import type { UploadInputProps } from '../../../../types/BagelForm'
import { Btn, IMAGE_FORMATS_REGEXP, Icon, Card, Image, pathKeyToURL, Loading, useI18n, resolveI18n } from '@bagelink/vue'
import { watch, ref, computed, useSlots } from 'vue'
import { useFileUpload } from './useFileUpload'
import { useBagelInputShell } from '../bagelInputShell'

const props = withDefaults(defineProps<UploadInputProps>(), {
	height: '215px',
	theme: 'dropzone',
	accept: '*',
	showIcon: true,
	icon: 'upload_2',
	iconSize: 2.5,
})

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

const { $t } = useI18n()
const slots = useSlots()
const {
	fileQueue,
	pathKeys,
	removeFile,
	flushQueue,
	addFile,
	browse,
	pk,
} = useFileUpload({
	disabled: props.disabled,
	dirPath: props.dirPath,
	multiple: props.multiple,
	accept: props.accept,
	capture: props.capture,
	namespace: props.id || 'upload',
	onFileQueued: async () => {
		await flushQueue()
		updateModelValue()
	},
	onChange: updateModelValue
})

watch(() => props.modelValue, val => pk.value = val ? [val].flat().filter(Boolean) : [], { immediate: true })

const { shellClass, shellStyle } = useBagelInputShell(props)
const hasValue = computed(() => pathKeys.value.length > 0 || fileQueue.value.length > 0)

const dropZoneText = computed(() => {
	const raw = props.dropPlaceholder ?? props.placeholder
	if (raw == null) { return $t('upload.dropPlaceholder') }
	const resolved = resolveI18n(raw)
	if (resolved != null && resolved !== '') { return resolved }
	return $t('upload.dropPlaceholder')
})

const showDropZonePlaceholder = computed(
	() => (!pathKeys.value.length && !fileQueue.value.length) || !!props.multiple
)

const isImage = (str: string) => IMAGE_FORMATS_REGEXP.test(str)

const isDragOver = ref(false)

function handleDrag(e: DragEvent, isDragging = false) {
	e.preventDefault()
	e.stopPropagation()
	if (!props.disabled) { isDragOver.value = isDragging }
}

function updateModelValue() {
	if (props.multiple) { emit('update:modelValue', pathKeys.value) }
	else { emit('update:modelValue', pathKeys.value[0] || undefined) }
}

async function handleDrop(e: DragEvent) {
	if (props.disabled) { return }
	e.preventDefault()
	e.stopPropagation()
	emit('addFileStart')
	addFile(e.dataTransfer?.files)
	isDragOver.value = false
}

function fileName(pathKey: string) {
	if (!pathKey || typeof pathKey !== 'string') { return 'file' }
	return pathKey.split('/').pop() || 'file'
}
</script>

<template>
	<div
		class="bagel-input" :class="[shellClass, { 'has-error': !!error, 'has-value': hasValue }]"
		:style="shellStyle" :data-field="name || id"
	>
		<label v-if="label">{{ label }}<span v-if="required"> *</span></label>
		<input v-if="required && !pathKeys.length" :name="name || id" placeholder="required" type="text" required class="pixel">
		<Card
			v-if="theme === 'basic'" outline class="flex p-05 gap-1" @dragover="(e: DragEvent) => handleDrag(e, true)"
			@drop="handleDrop"
		>
			<Btn
				v-if="!pathKeys.length && !fileQueue.length" class="px-1-5" icon="upload" outline
				:value="btnPlaceholder || $t('upload.upload')" @click="browse()"
			/>
			<!-- Loading state during upload -->
			<div v-if="fileQueue.length > 0" class="flex align-items-center gap-1 p-05">
				<Loading size="20" />
				<span class="txt-gray txt-12">
					{{ $t('upload.uploading', { count: fileQueue.length, plural: fileQueue.length > 1 ? 's' : '' }) }}
				</span>
			</div>

			<template v-for="path_key in pathKeys" :key="path_key">
				<div class="txt-gray txt-12 flex">
					<div class="m-05 flex opacity-8 z-99 gap-025">
						<Btn v-tooltip="'Delete'" color="gray" thin icon="delete" @click="removeFile(path_key)" />
						<Btn v-tooltip="'Replace'" color="gray" thin icon="autorenew" @click="browse()" />
						<Btn
							icon="download" color="gray" thin target="_blank" :href="pathKeyToURL(path_key)"
							:download="fileName(path_key)"
						/>
						<div class="flex gap-025 rounded pe-1 ps-05 py-025 -my-1 ">
							<Icon icon="draft" :size="1.5" />
							<p
								v-lightbox="{ src: pathKeyToURL(path_key), download: true }"
								class="ellipsis-1 word-break-all h-20 m-0 color-black txt16"
							>
								{{ fileName(path_key) }}
							</p>
						</div>
					</div>
				</div>
			</template>

			<span v-if="!pathKeys.length && !fileQueue.length" class="txt-gray txt-12">
				{{ noFilePlaceholder || $t('upload.noFile') }}
			</span>
		</Card>

		<div
			v-else class="fileUploadWrap" :class="{
				'fileDropZone': !pathKeys.length && !fileQueue.length,
				'dragover': isDragOver,
				'bgl_oval-upload': oval,
			}" :style="{ width, height }" @click="browse()" @dragover="(e) => handleDrag(e, true)" @drop="handleDrop"
			@dragleave="(e) => handleDrag(e)"
		>
			<slot name="files" :files="pathKeys" :fileQueue>
				<div v-if="multiple" class="bgl-multi-preview">
					<div
						v-for="path_key in pathKeys" :key="path_key"
						v-lightbox="{ src: pathKeyToURL(path_key), download: true }" class="multi-image-item-preview"
						:class="{ 'bgl_fill-image': fill }"
					>
						<Image v-if="isImage(path_key)" :pathKey="path_key" class="multi-preview" />
						<Icon v-else icon="description" class="multi-preview" />
						<p class="m-0">
							{{ fileName(path_key) }}
						</p>
						<Btn thin flat icon="delete" color="red" @click="removeFile(path_key)" />
					</div>
					<div
						v-for="file in fileQueue" :key="file.name" class="multi-image-item-preview"
						:class="{ 'bgl_fill-image': fill }"
					>
						<img v-if="isImage(file.file.type)" class="multi-preview" :src="file.url" alt="">
						<Icon v-else icon="description" class="multi-preview" />
						<p class="no-margin multi-preview-txt">
							{{ file.name }}
						</p>
						<div
							class="pie" :style="{ '--p': file.progress }" style="--b: 2px"
							:class="{ complete: file.progress === 100 }"
						>
							<span v-if="file.progress < 100" class="progress">
								{{ file.progress.toFixed(0) }}
							</span>
							<Icon class="success" icon="check_circle" />
						</div>
					</div>
				</div>

				<div v-else-if="pathKeys.length > 0 || fileQueue.length > 0" class="bgl-single-preview">
					<div
						v-for="path_key in pathKeys" :key="path_key" class="single-image-item-preview"
						:class="{ 'bgl_fill-image': fill }"
					>
						<div
							class="flex opacity-8 z-99 gap-025 absolute top-0 start-0"
							:class="{ 'mx-auto end-0 mt-1 justify-content-center': oval, 'm-05': !oval }"
						>
							<Btn
								v-tooltip="'Delete'" color="white" frame thin icon="delete"
								@click="removeFile(path_key)"
							/>
							<Btn v-tooltip="'Replace'" color="white" frame thin icon="autorenew" @click="browse()" />
							<Btn
								v-tooltip="'Download'" color="white" frame thin target="_blank" icon="download"
								:href="pathKeyToURL(path_key)" :download="fileName(path_key)"
							/>
						</div>
						<div v-if="isImage(path_key)" class="h-100">
							<Image
								v-lightbox="{ src: pathKeyToURL(path_key), download: true }" class="single-preview"
								:pathKey="path_key" alt=""
							/>
						</div>
						<Icon
							v-else v-lightbox="{ src: pathKeyToURL(path_key), download: true }" :size="4" weight="2"
							icon="description" class="color-primary w-100"
						/>
					</div>
					<div
						v-for="file in fileQueue" :key="file.name" class="single-image-item-preview"
						:class="{ 'bgl_fill-image': fill }"
					>
						<Loading
							type="bar" :progress="file.progress"
							class="absolute bottom-05 end start w-100px mx-auto rounded overflow-hidden"
						/>
						<img v-if="isImage(file.file.type)" class="single-preview opacity-5" :src="file.url" alt="">
					</div>
				</div>
			</slot>

			<slot
				v-if="showDropZonePlaceholder && slots['drop-placeholder']"
				name="drop-placeholder"
				:files="pathKeys"
				:file-queue="fileQueue"
				:browse="browse"
			/>
			<slot
				v-else-if="showDropZonePlaceholder"
				name="placeholder"
				:files="pathKeys"
				:file-queue="fileQueue"
				:browse="browse"
			>
				<p class="p-1 flex column hover fileUploadPlaceHolder justify-content-center mb-05 ">
					<Icon
						v-if="showIcon"
						:icon="icon"
						:size="iconSize"
						:mobile-size="iconMobileSize"
						class="user-select-none line-height-1"
					/>
					<span class=" pretty balance user-select-none ">
						{{ dropZoneText }}
					</span>
				</p>
			</slot>
		</div>
		<div v-if="error" class="error-message">{{ error }}</div>
	</div>
</template>

<style src="./upload.css" scoped></style>
