<template>
	<view class="l-upload" ref="uploadRef" :style="[styles]">
		<view class="l-upload__item" v-for="(file, index) in customFiles" :style="[itemStyle]" :key="file.url">
			<view class="l-upload__item-inner" :style="[innerStyle]">
				<slot name="file" :file="file" :index="index">
					<image class="l-upload__image" v-if="file.type == 'image'" :src="file.url" :data-file="file"
						:mode="imageFit" @click="onProofTap(index)" />
					<video class="l-upload__image" v-if="file.type == 'video'" :src="file.url" :data-file="file"
						:poster="file.thumb"  :autoplay="false" objectFit="contain" @click="onFileClick(index)" />
					<view class="l-upload__progress-mask" v-if="file.status != null && file.status != 'done'" :data-file="file" @click="onFileClick(index)">
						<template v-if="file.status == 'loading'">
							<l-loading class="l-upload__progress-loading" size="24px" color="white" />
							<text class="l-upload__progress-text" v-if="file.percent != null">{{file.percent}}%</text>
							<text class="l-upload__progress-text" v-else>{{loadingText}}</text>
						</template>
						<l-icon v-else class="l-upload__progress-icon"
							:name="file.status == 'reload' ? 'refresh' : 'close-circle'" size="48rpx" aria-hidden />
						<text v-if="file.status == 'reload' || file.status == 'failed'" class="l-upload__progress-text">
							{{file.status == 'reload' ? reloadText : failedText}}
						</text>
					</view>
					<view class="l-upload__delete-btn" aria-role="button" aria-label="删除" :data-index="index"
						@click="onDelete(index)">
						<l-icon name="close" size="16px" color="#fff" />
					</view>
				</slot>
			</view>
		</view>
		<view class="l-upload__item l-upload__item--add"  
			:class="{'l-upload__item--disabled':disabled}"
			:style="[itemStyle]" 
			aria-label="上传" 
			v-show="!multiple ? customFiles.length == 0: true"
			@click="onAddTap">
			<view class="l-upload__item-inner" :style="[innerStyle, {background: addBgColor}]">
				<slot>
					<l-icon class="l-upload__add-icon" :size="uploadIconSize" :name="uploadIcon" />
				</slot>
			</view>
		</view>
	</view>
</template>
<script lang="ts">
	// @ts-nocheck
	import { defineComponent, ref, computed, watch, onUnmounted } from '@/uni_modules/lime-shared/vue';
	import { unitConvert } from '@/uni_modules/lime-shared/unitConvert'
	import uploadProps from './props'
	import { chooseFiles } from './utils'
	import { UploadFile, ChooseFileOptions } from './type';
	export default defineComponent({
		name: 'l-upload',
		props: uploadProps,
		emit: ['fail', 'remove', 'success', 'click', 'add', 'input', 'update:modelValue'],
		setup(props, {expose, emit}){
			const customFiles = ref<UploadFile[]>(props.value ?? props.modelValue ?? props.defaultFiles ?? []);
			
			const styles = computed(()=> {
				const style:Record<string, string> = {}
				const gutter = unitConvert(props.gutter ?? 8) / 2 * -1;
				style['margin-left'] =  `${gutter}px`;
				style['margin-right'] =  `${gutter}px`;
				style['margin-top'] =  `${gutter}px`;
				return style
			})
			
			const itemStyle = computed(() => {
				const style:Record<string, string> = {}
				
				let column = props.column ?? 4;
				if(props.column) {
					style['width'] = `${100 / column}%`
				}
				if(props.gridWidth) {
					const gutter = unitConvert(props.gutter ?? 8)
					style['width'] = `${unitConvert(props.gridWidth) + gutter}px`
				}
				return style
			})
			
			const innerStyle = computed(()=>{
				const style:Record<string, string> = {};
				
				const gutter = unitConvert(props.gutter ?? 8) / 2
				style['margin'] = `${gutter}px`
				
				// if(props.gridWidth) {
				// 	style['width'] = props.gridWidth
				// }
				if(props.gridBgColor){
					style.set('background', props.gridBgColor!)
				}
				if(props.gridHeight) {
					style['height'] = props.gridHeight
				}
				return style
			})
			
			
			const onFileClick = (index : number) => {
				const file = customFiles.value[index]
				emit('click', { file })
			}
			const onProofTap = (index : number) => {
				onFileClick(index);
				if (props.disablePreview) return
				uni.previewImage({
					urls: customFiles.value.filter((file) : boolean => file.percent != -1).map((file) : string => file.url),
					current: index
				});
			}
			const onDelete = (index : number) => {
				const delFile = customFiles.value[index]
				customFiles.value = customFiles.value.filter((file, i) : boolean => index != i)
				emit('remove', { index, file: delFile })
			}
			
			let last = 0;
			const upload = (files: UploadFile[]) => {
				if(!props.autoUpload || props.action == null || props.action!.length < 5) return
				if(props.action == 'uniCloud') {
					let uploadImgs:Promise<UniCloudUploadFileResult>[] = [];
					files.forEach((file, index) =>{
						const promise = new Promise<UniCloudUploadFileResult>((resolve, reject) =>{
							uniCloud.uploadFile({
								filePath: file.url,
								cloudPath: file.name!.substring(file.name!.lastIndexOf('.')),
								onUploadProgress: (res)=>{
									file.status = 'loading'
									file.percent = Math.floor(res.loaded / res.total * 100)
								},
							}).then(res=>{
								file.path = res.fileID;
								file.status = 'done'
								resolve(res)
							}).catch(err=>{
								file.status = 'failed'
								reject(err)
							})
						})
						uploadImgs.push(promise as Promise<UniCloudUploadFileResult>)
					})
					
					Promise.all(uploadImgs).then(res =>{
						emit('success', res)
					}).catch(err => {
						emit('fail', err)
					})
				} else {
					let uploadImgs:Promise<UploadFileSuccess>[] = [];
					files.forEach((file, index) =>{
						const promise = new Promise<UploadFileSuccess>((resolve, reject) =>{
							const task = uni.uploadFile({
								url: props.action!,
								filePath: file.url,
								name: file.name,
								formData: props.formData,
								header: props.headers,
								success: (res) => {
									file.status = 'done'
									if(res.statusCode == 200) {
										if(typeof res.data == 'string') {
											try{
												const data = JSON.parse<UTSJSONObject>(res.data);
												const url = data?.getString('url');
												if(url != null) {
													file.path = url
												}
											}catch(e){
												//TODO handle the exception
											}
										}
									}
									resolve(res)
								},
								fail(err) {
									file.status = 'failed'
									reject(err)
								}
							});
							task.onProgressUpdate((res) => {
								file.status = 'loading'
								file.percent = res.progress
							});
						})
						uploadImgs.push(promise as Promise<UploadFileSuccess>)
					})
					Promise.all(uploadImgs).then(res =>{
						emit('success', res)
					}).catch(err => {
						emit('fail', err)
					})
				}
			};
			const customLimit = computed(() : number => props.max == 0 ? 20 : props.max - customFiles.value.length)
			const onAddTap = () => {
				if (props.disabled) return;
				chooseFiles({
					mediaType: props.mediaType,
					count: customLimit.value,
					sourceType: props.sourceType,
					sizeType: props.sizeType,
					sizeLimit: props.sizeLimit
				} as ChooseFileOptions).then((files) =>{
					last = customFiles.value.length
					customFiles.value = customFiles.value.concat(files) 
					const _files = customFiles.value.filter((it, i):boolean => i > last - 1)
					upload(_files)
					emit('add', _files)
				})
			}
			const stop = watch(customFiles, (v : UploadFile[]) => {
				emit('update:modelValue', v)
				// #ifdef VUE2
				emit('input', v)
				// #endif
			})
			// #ifdef VUE2
			const stopValue = watch(() => props.value, (v: UploadFile[])=>{
				if(v.length != customFiles.value.length){
					customFiles.value = v
				}
			})
			// #endif
			// #ifdef VUE3
			const stopValue = watch(() => props.modelValue, (v: UploadFile[])=>{
				if(v.length != customFiles.value.length){
					customFiles.value = v
				}
			})
			// #endif
			// #ifdef VUE3
			expose({
				remove: onDelete
			});
			// #endif
			
			
			onUnmounted(() => {
				stopValue()
				stop()
			})
			
			
			return {
				styles,
				customFiles,
				itemStyle,
				innerStyle,
				onProofTap,
				onDelete,
				onAddTap,
				onFileClick,
				// #ifdef VUE2
				remove: onDelete,
				// #endif
			}
		}
	})
	
</script>
<style lang="scss">
	@import './index';
</style>