<template>
    <div class="flex page-conatiner">
        <div class="left-box">
            <div class="menu-box">
                <div class="flex align-center menu-name">
                    <img class="icon" src="@/public/other/gongzidan/icon.png" alt="">
                    <span class="title">工资单</span>
                </div>
                <div class="menu-item" :class="{ active: currentType === 'paper' }" @click="currentType = 'paper'">纸质版
                </div>
                <div class="menu-item" :class="{ active: currentType === 'electronic' }"
                    @click="currentType = 'electronic'">电子版</div>
            </div>
            <img class="stay-tuned-img" src="@/public/common/stay-tuned.png" alt="">
        </div>
        <PaperPreview v-show="currentType === 'paper'" :formData="formData" ref="previewRef" />
        <ElectronicPreview v-show="currentType === 'electronic'" :formData="electronicFormData"
            ref="electronicPreviewRef" />
        <CommonEdit class="right-box-sticky" title="工资单编辑" v-model="currentFormData" :fields="currentFormFields"
            @saveDraft="saveDraft" @download="downloadPaper" />
    </div>
    <WarningFooter />
</template>
<script setup>
import { storeToRefs } from 'pinia'
import { useUserStore } from '@/stores/user'
import { ref, watch, inject, onMounted, computed } from 'vue'
import WarningFooter from '@/components/common/WarningFooter.vue'
import { ElMessage, ElMessageBox } from 'element-plus'
import html2canvas from 'html2canvas'
import { useRoute, useRouter } from 'vue-router'

import PaperPreview from './components/gongzidan/PaperPreview.vue'
import ElectronicPreview from './components/gongzidan/ElectronicPreview.vue'
import CommonEdit from '@/components/common/CommonEdit.vue'

const showPayment = inject('showPayment')

const route = useRoute()
const router = useRouter()
const workId = ref('')
const originalTitle = ref('')
const previewRef = ref(null)
const electronicPreviewRef = ref(null)
const currentType = ref('paper')
/**
 * 组件挂载后执行的初始化操作：
 * 1. 从 URL 路由参数获取当前的草稿 ID (id 或 workId)
 * 2. 如果存在 ID，则从本地存储 (localStorage) 读取对应的草稿数据
 * 3. 将读取到的草稿数据解析并回显至表单模型 (formData) 中，恢复上一次的编辑状态
 */
onMounted(async () => {
    const id = route.query.id || route.query.workId
    if (!id) return

    try {
        let drafts = []
        try {
            drafts = JSON.parse(localStorage.getItem('local_drafts') || '[]')
            if (!Array.isArray(drafts)) drafts = []
        } catch (e) { }

        const work = drafts.find(w => String(w.id) === String(id))
        if (work) {
            workId.value = id
            originalTitle.value = work.title || ''
            if (work.data_json) {
                const configData = typeof work.data_json === 'string' ? JSON.parse(work.data_json) : work.data_json
                if (configData._type === 'electronic') {
                    currentType.value = 'electronic'
                    Object.assign(electronicFormData.value, configData)
                } else {
                    currentType.value = 'paper'
                    Object.assign(formData.value, configData)
                }
            }
        }
    } catch (e) {
        console.error('获取草稿失败:', e)
    }
})

const userStore = useUserStore()

const currentYear = new Date().getFullYear().toString()
const currentMonth = (new Date().getMonth() + 1).toString()

const formData = ref({
    year: currentYear,
    month: currentMonth,
    job: '销售',
    name: '肖战',
    basicSalary: "10000",
    performanceSalary: "5000",
    fullAttendanceBonus: "1000",
    otherBonus: "1000",
    socialInsurance: "600",
    taxDeduction: "1000",
    attendanceDeduction: "500",
    otherDeduction: "0",
    totalSalary: "13900",
    totalDeduction: "1500",
    date: `${currentYear}-${currentMonth.padStart(2, '0')}-21`,
    netSalary: "12400",
})

const formFields = ref([
    { label: '时间', type: 'year-month', keys: ['year', 'month'] },
    { label: '岗位', type: 'text', key: 'job' },
    { label: '姓名', type: 'text', key: 'name' },
    { label: '基本工资', type: 'number', key: 'basicSalary' },
    { label: '绩效工资', type: 'number', key: 'performanceSalary' },
    { label: '全勤奖金', type: 'number', key: 'fullAttendanceBonus' },
    { label: '其它奖金', type: 'number', key: 'otherBonus' },
    { label: '社保缴纳', type: 'number', key: 'socialInsurance' },
    { label: '个税缴纳', type: 'number', key: 'taxDeduction' },
    { label: '考勤扣款', type: 'number', key: 'attendanceDeduction' },
    { label: '其他扣款', type: 'number', key: 'otherDeduction' },
])

const electronicFormData = ref({
    name: '肖战',
    department: '市场推广部',
    job: '推广专员',
    standardSalary: "7500",
    payableAttendanceDays: "20",
    personalLeaveDays: "0",
    sickLeaveDays: "0",
    actualAttendanceDays: "20",
    allowance: "200",
    performance: "1000",
    socialInsurance: "398.07",
    housingFund: "118",
    tax: "35.52",
    personalLeaveDeduction: "0",
    sickLeaveDeduction: "0",
    otherDeduction: "0",
    totalPayable: "8700",
    totalDeduction: "551.59",
    netSalary: "8148.41",
    remark: '餐饮饭卡补贴200元'
})

const electronicFormFields = ref([
    { label: '姓名', type: 'text', key: 'name' },
    { label: '任职部门', type: 'text', key: 'department' },
    { label: '职务', type: 'text', key: 'job' },
    { label: '专员薪酬标准', type: 'number', key: 'standardSalary' },
    { label: '应出勤天数', type: 'number', key: 'payableAttendanceDays' },
    { label: '事假', type: 'number', key: 'personalLeaveDays' },
    { label: '病假', type: 'number', key: 'sickLeaveDays' },
    { label: '实出勤天数', type: 'number', key: 'actualAttendanceDays' },
    { label: '补贴', type: 'number', key: 'allowance' },
    { label: '绩效', type: 'number', key: 'performance' },
    { label: '社保代扣', type: 'number', key: 'socialInsurance' },
    { label: '公积金代扣', type: 'number', key: 'housingFund' },
    { label: '所得税代扣', type: 'number', key: 'tax' },
    { label: '应扣事假', type: 'number', key: 'personalLeaveDeduction' },
    { label: '应扣病假', type: 'number', key: 'sickLeaveDeduction' },
    { label: '其他扣款', type: 'number', key: 'otherDeduction' },
    { label: '备注', type: 'text', key: 'remark' },
])

const currentFormData = computed({
    get: () => currentType.value === 'paper' ? formData.value : electronicFormData.value,
    set: (val) => {
        if (currentType.value === 'paper') formData.value = val
        else electronicFormData.value = val
    }
})

const currentFormFields = computed(() => currentType.value === 'paper' ? formFields.value : electronicFormFields.value)

/**
 * 监听表单内各个工资款项的变化：
 * 自动计算总工资 (基本 + 绩效 + 各类奖金)
 * 自动计算总扣款 (社保 + 个税 + 各类扣款)
 * 最终计算得出实发工资 (总工资 - 总扣款)
 */
watch(
    () => [
        formData.value.basicSalary,
        formData.value.performanceSalary,
        formData.value.fullAttendanceBonus,
        formData.value.otherBonus,
        formData.value.socialInsurance,
        formData.value.taxDeduction,
        formData.value.attendanceDeduction,
        formData.value.otherDeduction
    ],
    ([basicVal, perfVal, attBVal, othBVal, socVal, taxVal, attDVal, othDVal]) => {
        const basic = parseFloat(basicVal) || 0
        const perf = parseFloat(perfVal) || 0
        const attendanceBonus = parseFloat(attBVal) || 0
        const otherBonus = parseFloat(othBVal) || 0

        const social = parseFloat(socVal) || 0
        const tax = parseFloat(taxVal) || 0
        const attendDeduct = parseFloat(attDVal) || 0
        const otherDeduct = parseFloat(othDVal) || 0

        const totalSalary = basic + perf + attendanceBonus + otherBonus
        const totalDeduction = social + tax + attendDeduct + otherDeduct
        const netSalary = totalSalary - totalDeduction

        formData.value.totalSalary = totalSalary.toString()
        formData.value.totalDeduction = totalDeduction.toString()
        formData.value.netSalary = netSalary.toString()
    },
    { immediate: true }
)

/**
 * 监听电子版表单变化，自动计算总工资、总扣款和实发工资
 */
watch(
    () => [
        electronicFormData.value.standardSalary,
        electronicFormData.value.allowance,
        electronicFormData.value.performance,
        electronicFormData.value.socialInsurance,
        electronicFormData.value.housingFund,
        electronicFormData.value.tax,
        electronicFormData.value.personalLeaveDeduction,
        electronicFormData.value.sickLeaveDeduction,
        electronicFormData.value.otherDeduction
    ],
    ([std, allow, perf, soc, hf, tax, pLeave, sLeave, other]) => {
        const totalP = (parseFloat(std) || 0) + (parseFloat(allow) || 0) + (parseFloat(perf) || 0)
        const totalD = (parseFloat(soc) || 0) + (parseFloat(hf) || 0) + (parseFloat(tax) || 0) + (parseFloat(pLeave) || 0) + (parseFloat(sLeave) || 0) + (parseFloat(other) || 0)

        // 保留两位小数，如果以 .00 结尾则去掉
        electronicFormData.value.totalPayable = totalP.toFixed(2).replace(/\.00$/, '')
        electronicFormData.value.totalDeduction = totalD.toFixed(2).replace(/\.00$/, '')
        electronicFormData.value.netSalary = (totalP - totalD).toFixed(2).replace(/\.00$/, '')
    },
    { immediate: true }
)

/**
 * 随机生成工资单数据（待实现）
 * 可用于快速填充演示数据
 */
const randomGenerate = () => {
    // TODO: 实现随机生成逻辑
}
/**
 * 保存当前工资单数据为草稿：
 * 1. 验证用户是否已登录，未登录则拦截并打开登录弹窗
 * 2. 弹窗提示用户输入作品名称，若与现有作品同名则二次确认是否覆盖
 * 3. 利用 html2canvas 对左侧预览区进行截图，生成作品封面图
 * 4. 将表单数据及封面图一并存入本地存储 (localStorage) 的 local_drafts 列表中
 * 5. 更新 URL 路由的草稿 ID 并提示保存结果
 */
const saveDraft = async () => {
    if (!userStore.isLoggedIn) {
        ElMessage.warning('请先登录')
        router.replace({ query: { ...route.query, showLogin: 1 } })
        return
    }
    try {
        const defaultTitle = originalTitle.value || '工资单'
        const { value: title } = await ElMessageBox.prompt('请输入作品名称', '保存草稿', {
            confirmButtonText: '保存',
            cancelButtonText: '取消',
            inputValue: defaultTitle,
            inputPlaceholder: '输入名称（同名将提示覆盖，异名将新建）',
        })
        if (!title) return

        let drafts = []
        try {
            drafts = JSON.parse(localStorage.getItem('local_drafts') || '[]')
            if (!Array.isArray(drafts)) drafts = []
        } catch (e) {
            drafts = []
        }

        let draftId = ''
        let isOverwriteOther = false

        if (title !== originalTitle.value) {
            const existIndex = drafts.findIndex(w => w.title === title && w.type === 'gongzidan')
            if (existIndex !== -1) {
                await ElMessageBox.confirm(`已存在同名作品「${title}」，是否覆盖该作品？`, '提示', {
                    confirmButtonText: '覆盖',
                    cancelButtonText: '取消',
                    type: 'warning'
                })
                draftId = drafts[existIndex].id
                isOverwriteOther = true
            } else {
                draftId = 'draft_' + Date.now()
            }
        } else {
            draftId = workId.value || ('draft_' + Date.now())
        }

        let coverImg = ''
        const el = currentType.value === 'paper' ? previewRef.value?.mainBoxRef : electronicPreviewRef.value?.mainBoxRef
        if (el) {
            let widthSize = 200;
            if (currentType.value === 'electronic') {
                widthSize = 150;
            }
            try {
                const canvas = await html2canvas(el, {
                    scale: widthSize / el.offsetWidth, // 固定生成 150px 宽度的图片
                    useCORS: true
                })
                coverImg = canvas.toDataURL('image/jpeg', 0.6)
            } catch (err) {
                console.error('截图生成失败', err)
            }
        }

        const saveData = currentType.value === 'paper'
            ? { ...formData.value, _type: 'paper' }
            : { ...electronicFormData.value, _type: 'electronic' }

        const payload = {
            id: draftId,
            title: title,
            type: 'gongzidan',
            page_router: '/gongzidan',
            data_json: JSON.stringify(saveData),
            cover_img: coverImg,
            update_time: Date.now()
        }

        let isSelfUpdate = false
        if (isOverwriteOther) {
            const existIndex = drafts.findIndex(w => String(w.id) === String(draftId))
            if (existIndex !== -1) drafts[existIndex] = payload
        } else {
            const selfIndex = drafts.findIndex(w => String(w.id) === String(draftId))
            if (selfIndex !== -1) {
                drafts[selfIndex] = payload
                isSelfUpdate = true
            } else {
                drafts.unshift(payload)
            }
        }

        localStorage.setItem('local_drafts', JSON.stringify(drafts))
        workId.value = payload.id
        originalTitle.value = payload.title

        if (!route.query.id || isOverwriteOther) {
            router.replace({ query: { id: draftId } })
        }

        let msg = '已新增草稿'
        if (isOverwriteOther) msg = '草稿已覆盖保存'
        else if (isSelfUpdate) msg = '草稿已更新'
        ElMessage.success(msg)
    } catch (e) {
        if (e !== 'cancel') {
            console.error(e)
            ElMessage.error('保存失败')
        }
    }
}

/**
 * 下载工资单图片：
 * 1. 验证用户是否已登录，以及是否拥有 VIP 权限（非 VIP 拦截并呼出支付弹窗）
 * 2. 获取预览区域的 DOM 节点 (mainBoxRef)
 * 3. 利用 html2canvas 对 DOM 进行高清渲染截图 (scale: 2)
 * 4. 在渲染副本 (onclone) 中，临时移除自带的水印节点 (watermark-overlay)
 * 5. 渲染完成后转为 Blob 数据，创建隐式 <a> 标签触发浏览器下载，最后清理临时链接
 */
const downloadPaper = async () => {
    if (!userStore.isLoggedIn) {
        ElMessage.warning('请先登录后再下载')
        router.replace({ query: { ...route.query, showLogin: 1 } })
        return
    }
    if (!userStore.isVip) {
        showPayment?.()
        return
    }


    const el = currentType.value === 'paper' ? previewRef.value?.mainBoxRef : electronicPreviewRef.value?.mainBoxRef
    if (!el) {
        ElMessage.error('预览未就绪，请稍后重试')
        return
    }
    try {
        const canvas = await html2canvas(el, {
            scale: 2,
            useCORS: true,
            onclone: (clonedDoc) => {
                const watermark = clonedDoc.querySelector('.watermark-overlay')
                if (watermark) {
                    watermark.remove()
                }
            }
        })
        canvas.toBlob((blob) => {
            if (!blob) {
                ElMessage.error('图片生成失败')
                return
            }
            const url = URL.createObjectURL(blob)
            const link = document.createElement('a')
            link.download = `gongzidan-${Date.now()}.png`
            link.href = url
            document.body.appendChild(link)
            link.click()
            document.body.removeChild(link)
            URL.revokeObjectURL(url)
            ElMessage.success('下载成功')
        }, 'image/png')
    } catch (e) {
        ElMessage.error('下载失败：' + e.message)
    }
}
</script>
<style scoped lang="scss">
.flex {
    display: flex;
}

.flex-col {
    display: flex;
    flex-direction: column;
}

.align-center {
    align-items: center;
}

.flex-1 {
    flex: 1;
}

.shrink {
    flex-shrink: 0;
}

.w-full {
    width: 100%;
}

.h-full {
    height: 100%;
}

.page-conatiner {
    padding: 47px;
    padding-left: 66px;
    margin: 17px auto 0;
    width: fit-content;
    justify-content: center;
    align-items: flex-start;

    .left-box {
        position: sticky;
        top: 176px;
        z-index: 10;
    }

    .right-box-sticky {
        position: sticky;
        top: 176px;
        z-index: 10;
    }

    .menu-box {
        width: 200px;
        padding: 16px;
        background-color: #FFFFFF;
        border-radius: 18px;
        box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.1);

        .menu-name {
            background: #ECECFF;
            border-radius: 12px 12px 12px 12px;
            padding: 12px;
        }

        .icon {
            width: 32px;
            height: 32px;
            margin-right: 6px;
        }

        .title {
            width: 90px;
            height: 20px;
            font-family: Source Han Sans, Source Han Sans;
            font-weight: 500;
            font-size: 18px;
            line-height: 20px;
            text-align: left;
            font-style: normal;
            text-transform: none;
            background: linear-gradient(88.42188424578676deg, #6825DB 0%, #5066D4 100%);
            background-clip: text;
            -webkit-background-clip: text;
            -webkit-text-fill-color: transparent;
        }

        .menu-item {
            margin-top: 16px;
            font-size: 18px;
            color: #1A1A1A;
            height: 37px;
            line-height: 37px;
            padding-left: 12px;
            border-radius: 8px;
            cursor: pointer;

            &:hover {
                background-color: #F7F8FF;
            }

            &.active {
                color: #FFFFFF;
                background: linear-gradient(215deg, #A679F4 7.14%, #778CF5 100%);
                border-radius: 8px 8px 8px 8px;
                border-image: linear-gradient(215deg, rgba(166.00000530481339, 121.00000038743019, 244.0000006556511, 1), rgba(119.00000050663948, 140.00000685453415, 245.00000059604645, 1)) 1 1;
            }
        }
    }

    .stay-tuned-img {
        width: 200px;
        height: 145px;
        margin-top: 22px;
        background-color: #FFFFFF;
        box-shadow: 0px 0px 5px 0px rgba(0, 0, 0, 0.1);
        border-radius: 18px 18px 18px 18px;
    }
}
</style>