<script setup lang="ts">
    import md5 from 'crypto-js/md5'

    const props = defineProps({
        width: {
            type: [String, Number],
            default: '320',
        },
        height: {
            type: [String, Number],
            default: '240',
        },
        radius: {
            type: [String, Number],
            default: 0,
        },
        mode: {
            type: String,
            default: 'scaleToFill',
        },
        background: {
            type: String,
            default: '#F7F7F7',
        },
        src: {
            type: String,
            required: true,
        },
        debug: {
            type: Boolean,
            default: false,
        },
    })

    const srcImage = ref()

    const hashCacheKey = ref()
    onMounted(async () => {
        await tryCache()
    })

    // 监听 src 变化
    watch(
        () => props.src,
        async () => await tryCache(),
    )

    function log(...args: any[]) {
        if (props.debug) {
            console.log('[CacheImage]', ...args)
        }
    }

    // 尝试缓存图片，如果失败则使用原始图片
    async function tryCache() {
        let url = props.src
        if (!url) {
            return
        }

        // 如果是网络图片，则缓存到本地
        if (url.startsWith('http')) {
            // #ifdef APP-PLUS
            const hash = md5(url).toString()
            hashCacheKey.value = `G_CACHE_IMAGE_${hash}`
            if (uni.getStorageSync(hashCacheKey.value)) {
                log('cache hit', url)
                url = uni.getStorageSync(hashCacheKey.value)
            } else {
                log('cache miss', url)
                try {
                    const res = await uni.downloadFile({ url })
                    if (res.statusCode === 200) {
                        const { savedFilePath } = await new Promise<UniApp.SaveFileSuccess>((resolve, reject) => {
                            uni.saveFile({
                                tempFilePath: res.tempFilePath,
                                success: (res) => resolve(res),
                                fail: (err) => reject(err),
                            })
                        })
                        url = `${savedFilePath}`

                        // 缓存图片本地地址
                        uni.setStorageSync(hashCacheKey.value, url)
                    } else {
                        log('cache error', url, res)
                        url = props.src
                    }
                } catch (e) {
                    console.error(e)
                }
            }
            log(props.src, '=>', url, hash, hashCacheKey.value)
            // #endif
        }

        srcImage.value = url
    }

    const hasError = ref(false)

    function onError() {
        if (hasError.value) {
            return
        }

        hasError.value = true
        srcImage.value = props.src
        // 清除缓存
        hashCacheKey.value && uni.removeStorageSync(hashCacheKey.value)
        console.warn('CacheImage cache error')
    }
</script>

<template>
    <fui-lazyload
        v-bind="$attrs"
        :mode="props.mode"
        :width="props.width"
        :height="props.height"
        :radius="props.radius"
        :background="props.background"
        :src="srcImage"
        @error="onError"
    >
        <slot></slot>
    </fui-lazyload>
</template>
