import type { MaybeRefOrGetter } from 'vue'
import type { BglFile, QueueFile } from './upload.types'
import { useBagel } from '@bagelink/vue'
import { ref, computed, onMounted, toValue, } from 'vue'
import { files } from './upload'

interface UseFileUploadProps {
	multiple?: boolean
	dirPath?: MaybeRefOrGetter<string>
	accept?: string
	disabled?: boolean
	namespace?: string
	onFileQueued?: (files: QueueFile[]) => void
}

export function useFileUpload(props: UseFileUploadProps = {}) {
	files.setBaseUrl(useBagel().host)

	const namespace = props.namespace || 'default'

	const fileQueue = ref<QueueFile[]>([])
	const storageFiles = ref<BglFile[]>([])
	const pk = ref<string[]>([])

	// Computed
	const pathKeys = computed(() => {
		const storagePathKeys = storageFiles.value.map(file => file.path_key)
		return [...pk.value, ...storagePathKeys]
	})

	// File handling methods
	const fileToUrl = (file: File) => URL.createObjectURL(file)

	function addFile(file?: File | File[] | FileList | null) {
		if (!file) return

		let filesToAdd: File[] = []

		if (file instanceof File) {
			filesToAdd = [file]
		} else if (file instanceof FileList) {
			filesToAdd = Array.from(file)
		} else if (Array.isArray(file)) {
			filesToAdd = file
		}

		const newQueueFiles = filesToAdd.map(f => ({
			url: fileToUrl(f),
			name: f.name,
			file: f,
			progress: 0,
			namespace
		}))
		if (props.multiple) {
			fileQueue.value.push(...newQueueFiles)
		} else {
			fileQueue.value = newQueueFiles
		}

		// Call the onFilesQueued callback if provided
		if (props.onFileQueued && newQueueFiles.length > 0) {
			props.onFileQueued(newQueueFiles)
		}
	}

	async function removeFile(pathKeyOrFile: string | File | QueueFile) {
		if (typeof pathKeyOrFile === 'string') {
			// Remove from both lists
			storageFiles.value = storageFiles.value.filter(file => file.path_key !== pathKeyOrFile)

			const pathKeyIndex = pk.value.indexOf(pathKeyOrFile)
			if (pathKeyIndex !== -1) {
				pk.value.splice(pathKeyIndex, 1)
			}

			try {
				await files.delete(pathKeyOrFile)
			} catch (error) {
				console.error('Error deleting file:', error)
			}
		} else if (pathKeyOrFile) {
			// For File or QueueFile, check if it's in our queue for this namespace
			const fileToRemove = pathKeyOrFile instanceof File
				? { name: pathKeyOrFile.name }
				: pathKeyOrFile

			const index = fileQueue.value.findIndex(queueFile => queueFile.file.name === fileToRemove.name
				&& queueFile.namespace === namespace
			)

			if (index !== -1) {
				fileQueue.value.splice(index, 1)
			}
		}
	}
	async function flushQueue() {
		// Only process files in the current namespace
		const namespaceQueue = fileQueue.value.filter(file => file.namespace === namespace)

		for (const file of namespaceQueue) {
			file.uploading = true

			// If not multiple, replace the existing file
			if (!props.multiple) {
				pk.value.splice(0, 1)
			}

			try {
				const { data } = await files.upload(file.file, {
					onUploadProgress: (e: ProgressEvent) => {
						file.progress = (e.loaded / e.total) * 100 - 1
					},
					dirPath: toValue(props.dirPath)
				})
				pk.value.push(data.path_key)
			} catch (error) {
				console.error('Error uploading file:', error)
			}
		}

		// Clear only files in the current namespace from the queue
		fileQueue.value = fileQueue.value.filter(file => file.namespace !== namespace)
	}

	// UI interaction
	function browse(autoFlush = false) {
		if (props.disabled) return

		const input = document.createElement('input')
		input.type = 'file'
		input.multiple = !!props.multiple
		input.accept = props.accept || ''

		input.onchange = (e: Event) => {
			addFile((e.target as HTMLInputElement).files)
			if (autoFlush) {
				flushQueue()
			}
		}

		input.click()
	}

	// Load initial files
	onMounted(() => {
		const dirPath = toValue(props.dirPath)
		if (dirPath) {
			files.list(dirPath)
				.then((response) => {
					const responseData = Array.isArray(response.data)
						? response.data
						: [response.data]
					storageFiles.value.push(...responseData)
				})
				.catch((error) => { console.error('Error loading files:', error) })
		}
	})

	return {
		fileQueue,
		storageFiles,
		pk,
		pathKeys,
		fileToUrl,
		removeFile,
		flushQueue,
		addFile,
		browse,
		namespace
	}
}
