<template>
    <div class="input file" :class="{ suffix: $slots.icon, disabled: disabled, valuable }">
        <template v-if="valuable">
            <slot :key="modelValue" name="valuable" />
        </template>
        <input v-if="!maxLen || maxLen > modelValue.length" ref="inputRef" title="" class="ui-text" type="file" :accept="accept" :multiple="multiple" @change="selectFileHandler" />
        <template v-if="!$slots.replace">
            <span class="replace">
                <div v-if="!valuable" class="placeholder">
                    <p><ui-icon type="add" /></p>
                    <p>{{ placeholder }}</p>
                    <p class="bottom">
                        <template v-if="!othPlaceholder">
                            <template v-if="accept">支持 {{ accept }} 等格式,</template>
                            <template v-if="normalizeScale">宽*高比例 {{ scale }},</template>
                            <template v-if="maxSize">大小不超过 {{ sizeStr }}{{ maxLen ? ',' : '' }}</template>
                            <template v-if="maxLen">个数不超过 {{ maxLen }}个</template>
                        </template>
                        <template v-else>
                            {{ othPlaceholder }}
                        </template>
                    </p>
                </div>

                <span v-else-if="!maxLen || maxLen > modelValue.length">
                    {{ multiple ? '继续添加' : '替换' }}
                </span>
                <span v-if="maxLen && modelValue.length" class="tj">
                    <span>{{ modelValue.length || 0 }}</span> / {{ maxLen }}
                </span>
            </span>
        </template>
        <div v-else class="use-replace">
            <slot name="replace" />
        </div>
    </div>
</template>

<script setup lang="ts">
import { computed, defineEmits, defineExpose, defineProps, ref } from 'vue'
import { toRawType } from '@kankan/utils'
import Dialog from '@kankan/components/basic/dialog'
import { fileProps } from './file'
// import Message from '../message';
// import { useI18n } from '@/i18n'
// const { t } = useI18n({ useScope: 'global' })
const props = defineProps(fileProps)
const emit = defineEmits(['update:modelValue'])
const inputRef = ref(null)
const normalizeScale = computed(() => {
    if (props.scale) {
        const [w, h] = props.scale.split(':')
        if (Number(w) && Number(h)) {
            return [Number(w), Number(h)]
        }
    }
    return []
})

const valuable = computed(() => (Array.isArray(props.modelValue) ? props.modelValue.length : !!props.modelValue))
const sizeStr = computed(() => props.maxSize && `${props.maxSize / 1024 / 1024}MB`)

const supports = {
    image: {
        types: ['image/jpeg', 'image/jpg', 'image/png', 'image/gif', 'image/webp'],
        preview(file, url) {
            return new Promise((resolve, reject) => {
                const img = new Image()
                img.onload = () => resolve([img.width, img.height, file])
                img.onerror = reject
                img.src = url
            })
        },
    },
    video: {
        types: ['video/mp4'],
        preview(file, url) {
            return new Promise((resolve, reject) => {
                const video = document.createElement('video')
                video.preload = 'metadata'
                video.onloadedmetadata = () => resolve([video.videoWidth, video.videoHeight, file])
                video.onerror = reject
                video.src = url
            })
        },
    },
}

const producePreviews = files =>
    Promise.all(
        files.map(
            file =>
                new Promise((resolve, reject) => {
                    const fr = new FileReader()
                    fr.onloadend = e => resolve(e.target.result)
                    fr.onerror = e => loaderror(file, reject(e))
                    fr.readAsDataURL(file)
                })
        )
    )

const calcScale = (w, h) => Number.parseInt((w / h) * 1000)

const selectFileHandler = async ev => {
    const fileEl = ev.target
    const files = Array.from(fileEl.files)
    const previewError = (e, msg = `预览加载失败！`) => {
        console.error(e)
        // Message.error(msg)
        Dialog.toast({
            content: msg,
            type: 'error',
        })
        fileEl.value = ''
    }

    if (props.accept) {
        for (const file of files) {
            const accepts = props.accept.split(',').map(atom => {
                return atom.trim()
            })
            const hname = file.name.slice(file.name.lastIndexOf('.')).toLowerCase()
            if (!accepts.includes(hname)) {
                // return previewError('格式错误', `仅支持${props.accept}格式文件`)
                const accept = props.accept.split('.').join('').replace(',', '/').toLowerCase()
                return previewError('格式错误', `${t('limit.formFile', { form: accept })}`)
            }
        }
    }

    let previews
    if (props.preview || normalizeScale.value) {
        try {
            previews = await producePreviews(files)
        } catch (e) {
            return previewError(e)
        }
    }

    if (normalizeScale.value) {
        const sizesConfirm = []
        for (const [i, file] of files.entries()) {
            const support = Object.values(supports).find(support => support.types.includes(file.type))
            if (support) {
                sizesConfirm.push(support.preview(file, previews[i]))
            }
        }

        let sizes
        try {
            sizes = await Promise.all(sizesConfirm)
        } catch (e) {
            return previewError(e)
        }

        for (const [w, h, file] of sizes) {
            const scaleDiff = calcScale(...normalizeScale.value) - calcScale(w, h)

            if (Math.abs(scaleDiff) > 300) {
                // return previewError('error scale', `${file.name}的比例部位不为${props.scale}`)
                return previewError('error scale', `${t('limit.scaleFile', { fileName: file.name, scale: props.scale })}`)
            }
        }
    }

    if (props.maxSize) {
        for (const file of files) {
            if (file.size > props.maxSize) {
                // return previewError('error size', `${file.name}的大小超过${sizeStr.value}`)
                // return previewError('error size', `${file.name}的大小超过${sizeStr.value}`)

                const accept = props.accept.split('.').join('').replace(',', '/').toLowerCase()
                return previewError('格式错误', `${t('limit.formSize', { size: sizeStr.value, form: accept })}`)
            }
        }
    }

    const value = props.modelValue ? (props.multiple ? (toRawType(props.modelValue) === 'Array' ? props.modelValue : [props.modelValue]) : null) : props.multiple ? [] : null

    const emitData = props.multiple
        ? props.preview
            ? [...value, ...files.map((file, i) => ({ file, preview: previews[i] }))]
            : [...value, files]
        : props.preview
        ? { file: files[0], preview: previews[0] }
        : files[0]

    if (Array.isArray(emitData) && props.maxLen && emitData.length > props.maxLen) {
        // return previewError('err len', `最多仅支持${props.maxLen}个文件！`)
        return previewError('err len', `${t('limit.maxLengthFile', { length: props.maxLen })}`)
    }

    emit('update:modelValue', emitData)
    fileEl.value = ''
}

defineExpose({
    input: inputRef,
})
</script>
