<template>
    <div class="x-qrcode" :style="{
        width: `${size}px`,
        height: `${size}px`,
        
    }" style="display: flex;align-items: center;flex-direction: column;justify-content: center;margin: 20px;">
        <template v-if="'active' !== status">
            <div class="x-qrcode__mask">
                <template v-if="'loading' === status">
                    <a-spin></a-spin>
                </template>
                <template v-if="'expired' === status">
                    <div>二维码已过期</div>
                    <a-button type="link" class="x-qrcode__reload-btn" @click="handleRefresh">
                        <template #icon>
                            <reload-outlined></reload-outlined>
                        </template>
                        点击刷新
                    </a-button>
                </template>
            </div>
        </template>
        <canvas ref="qrCodeRef"></canvas>

        <!-- 添加下载按钮 -->
        <a-button type="primary" v-if="status === 'active'" @click="handleDownload" style="margin-top:20px">
            <template #icon>
                <DownloadOutlined />
            </template>
            下载
        </a-button>
    </div>
</template>

<script setup>
import QRCode from 'qrcode'
import { onMounted, ref, toRefs, watch } from 'vue'

import { ReloadOutlined, DownloadOutlined } from '@ant-design/icons-vue'

defineOptions({
    name: 'XQrCode',
})
/**
 * 二维码
 * @property {string} value 内容
 * @property {number} size 大小。默认：120
 * @property {string} color 颜色。默认：#000
 * @property {string} backgroundColor 背景色。默认：#fff
 * @property {string} icon icon 的地址（目前只支持图片地址）
 * @property {number} iconSize icon 的大小。默认：30
 * @property {number} iconPadding icon 间距。默认：0
 * @property {string} iconBackgroundColor icon 背景色
 * @property {string} errorLevel 纠错等级。默认：M，【L=low, M=medium, Q=quartile, H=high】
 * @property {string} status 状态，【active=有效，loading=加载中，expired=已过期】
 * @property {string} downloadFileName 下载文件名（不带扩展名）。默认：qrcode
 */
const props = defineProps({
    value: {
        type: String,
        required: true,
        default: '',
    },
    size: {
        type: Number,
        default: 120,
    },
    color: {
        type: String,
        default: '#000',
    },
    backgroundColor: {
        type: String,
        default: '#fff',
    },
    icon: {
        type: String,
        default: '',
    },
    iconSize: {
        type: Number,
        default: 30,
    },
    iconPadding: {
        type: Number,
        default: 0,
    },
    iconBackgroundColor: {
        type: String,
        default: '',
    },
    errorLevel: {
        type: String,
        default: 'M',
    },
    status: {
        type: String,
        default: 'active',
    },
    downloadFileName: {
        type: String,
        default: 'qrcode'
    }
})

const emit = defineEmits(['refresh', 'download'])

const qrCodeRef = ref()

watch(
    () => toRefs(props),
    () => {
        init()
    },
    {
        deep: true,
    }
)

onMounted(() => {
    init()
})

/**
 * 初始化
 * @return {Promise<void>}
 */
async function init() {
    await renderQRCode()
    if (props.icon) {
        await renderIcon()
    }
    emit('ready', qrCodeRef.value)
}

/**
 * 渲染二维码
 * @return {Promise<unknown>}
 */
async function renderQRCode() {
    return new Promise((resolve) => {
        ; (async () => {
            await QRCode.toCanvas(qrCodeRef.value, props.value, {
                width: props.size,
                color: {
                    dark: props.color,
                    light: props.backgroundColor,
                },
                errorCorrectionLevel: props.errorLevel,
                margin: 0,
            })
            resolve()
        })()
    })
}

/**
 * 渲染 icon
 * @return {Promise<unknown>}
 */
async function renderIcon() {
    return new Promise((resolve) => {
        let img = new Image()
        img.src = props.icon
        const logoPos = (props.size - props.iconSize) / 2
        const rectSize = props.iconSize + props.iconPadding
        const rectPos = (props.size - rectSize) / 2
        let ctx = qrCodeRef.value.getContext('2d')
        img.onload = () => {
            if (props.iconBackgroundColor) {
                ctx.fillStyle = props.iconBackgroundColor
                ctx.fillRect(rectPos, rectPos, rectSize, rectSize)
            }
            ctx.drawImage(img, logoPos, logoPos, props.iconSize, props.iconSize)
            resolve()
        }
    })
}

/**
 * 刷新
 */
function handleRefresh() {
    emit('refresh')
}

/**
 * 下载二维码
 */
function handleDownload() {
    if (!qrCodeRef.value) return;

    try {
        const canvas = qrCodeRef.value;
        const dataUrl = canvas.toDataURL('image/png');
        const link = document.createElement('a');
        link.href = dataUrl;
        link.download = `${props.downloadFileName || 'qrcode'}.png`;
        document.body.appendChild(link);
        link.click();
        document.body.removeChild(link);

        // 触发下载事件
        emit('download', dataUrl);
    } catch (error) {
        console.error('下载二维码失败:', error);
    }
}

/**
 * 转换成 data URI
 * @returns {Promise<*>}
 */
async function toDataURL() {
    return qrCodeRef.value.toDataURL('image/png')
}

defineExpose({
    toDataURL,
    handleDownload
})
</script>

<style lang="less" scoped>
.x-qrcode {
    position: relative;
    display: inline-block;

    &__mask {
        background: rgba(255, 255, 255, 0.96);
        position: absolute;
        width: 100%;
        height: 100%;
        z-index: 10;
        display: flex;
        align-items: center;
        justify-content: center;
        flex-direction: column;

        .ant-spin {
            line-height: 1;
        }
    }

    /* 下载按钮样式 */
    &__download {

        right: 4px;
        bottom: 4px;
        width: 24px;
        height: 24px;
        background: rgba(0, 0, 0, 0.5);
        border-radius: 4px;
        display: flex;
        align-items: center;
        justify-content: center;
        cursor: pointer;
        transition: all 0.3s;
        z-index: 20;

        &:hover {
            background: rgba(0, 0, 0, 0.7);
            transform: scale(1.1);
        }
    }

    &__download-icon {
        color: white;
        font-size: 14px;
    }
}
</style>