<script lang="ts">
    import type { PropType } from 'vue'
    import { defineComponent, onMounted, ref, unref, watch } from 'vue'
    import { toDataURL } from 'qrcode'
    import type { LogoType, QRCodeRenderersOptions } from './qrcodePlus'
    import { toCanvas } from './qrcodePlus'
    import { downloadByUrl } from '/@/utils/file/download'
    import type { QrcodeDoneEventParams } from './typing'

    export default defineComponent({
        name: 'QrCode',
        props: {
            value: {
                type: [String, Array] as PropType<string | any[]>,
                default: null,
            },
            // 参数
            options: {
                type: Object as PropType<QRCodeRenderersOptions>,
                default: null,
            },
            // 宽度
            width: {
                type: Number as PropType<number>,
                default: 200,
            },
            // 中间logo图标
            logo: {
                type: [String, Object] as PropType<Partial<LogoType> | string>,
                default: '',
            },
            // img 不支持内嵌logo
            tag: {
                type: String as PropType<'canvas' | 'img'>,
                default: 'canvas',
                validator: (v: string) => ['canvas', 'img'].includes(v),
            },
        },
        emits: { done: (data: QrcodeDoneEventParams) => !!data, error: (error: any) => !!error },
        setup(props, { emit }) {
            const wrapRef = ref<HTMLCanvasElement | HTMLImageElement | null>(null)
            async function createQrcode() {
                try {
                    const { tag, value, options = {}, width, logo } = props
                    const renderValue = String(value)
                    const wrapEl = unref(wrapRef)

                    if (!wrapEl) return

                    if (tag === 'canvas') {
                        const url: string = await toCanvas({
                            canvas: wrapEl,
                            width,
                            logo: logo as any,
                            content: renderValue,
                            options: options || {},
                        })
                        emit('done', { url, ctx: (wrapEl as HTMLCanvasElement).getContext('2d') })
                        return
                    }

                    if (tag === 'img') {
                        const url = await toDataURL(renderValue, {
                            errorCorrectionLevel: 'H',
                            width,
                            ...options,
                        })
                        ;(unref(wrapRef) as HTMLImageElement).src = url
                        emit('done', { url })
                    }
                } catch (error) {
                    emit('error', error)
                }
            }
            /**
             * file download
             */
            function download(fileName?: string) {
                let url = ''
                const wrapEl = unref(wrapRef)
                if (wrapEl instanceof HTMLCanvasElement) {
                    url = wrapEl.toDataURL()
                } else if (wrapEl instanceof HTMLImageElement) {
                    url = wrapEl.src
                }
                if (!url) return
                downloadByUrl({
                    url,
                    fileName,
                })
            }

            onMounted(createQrcode)

            // 监听参数变化重新生成二维码
            watch(
                props,
                () => {
                    createQrcode()
                },
                {
                    deep: true,
                },
            )

            return { wrapRef, download }
        },
    })
</script>

<template>
    <div>
        <component :is="tag" ref="wrapRef" />
    </div>
</template>
