<template>
    <view>
        <cu-custom :backUrl="'/pages/index/index'" :isBack="true" bgColor="bg-gradual-blue">
            <block slot="content">报损申请</block>
        </cu-custom>

        <u--form :model="inputForm" labelWidth="100px" class="u-form" labelPosition="left" :rules="rules"
            ref="inputForm">
            <u-form-item label="报损编号" borderBottom prop="lossNo">
                <u--input placeholder="自动生成" v-model="inputForm.lossNo" disabled></u--input>
            </u-form-item>
            <u-form-item label="经办人" borderBottom prop="handledBy">
                <u--input v-model="inputForm.handledBy" disabled></u--input>
            </u-form-item>
            <u-form-item label="经办部门" borderBottom prop="handledByOfficeName">
                <u--input v-model="inputForm.handledByOfficeName" disabled></u--input>
            </u-form-item>
            <u-form-item label="报损时间" borderBottom prop="lossDate" :required="true">
                <el-date-picker v-model="inputForm.lossDate" type="date" placeholder="请选择报损时间" style="width:100%"
                    placement="bottom-start" clearable :disabled="nodeFlag">
                </el-date-picker>
            </u-form-item>
            <u-form-item label="备注" borderBottom prop="remarks">
                <u--textarea placeholder="请填写备注信息" :rows="4" :maxlength="500" v-model="inputForm.remarks"
                    :disabled="nodeFlag"></u--textarea>
            </u-form-item>

            <view class="section-wrap">
                <view class="section-title">报损明细</view>
                <view class="section-tip">报损数量按最小单位填写</view>

                <view v-for="(item, index) in inputForm.detailInfos" :key="item.id || index" class="detail-card">
                    <view class="detail-card-title">报损详情 {{ index + 1 }}</view>

                    <u-form-item label="报损人" :prop="'detailInfos[' + index + '].recipientAgent'" :required="true">
                        <u--input v-model="inputForm.detailInfos[index].recipientAgent" placeholder="请选择报损人"
                            :disabled="nodeFlag" @focus="openUserPullForm(index)" clearable></u--input>
                    </u-form-item>
                    <u-form-item label="报损人部门" :prop="'detailInfos[' + index + '].recipientOffice'">
                        <u--input v-model="inputForm.detailInfos[index].recipientOffice" disabled></u--input>
                    </u-form-item>
                    <loss-goods-selector :rowIndex="index" :inputForm="inputForm" :disabled="nodeFlag"
                        @selected="handleGoodsSelected"></loss-goods-selector>

                    <u-form-item label="品牌" :prop="'detailInfos[' + index + '].brand'">
                        <u--input v-model="inputForm.detailInfos[index].brand" disabled></u--input>
                    </u-form-item>
                    <u-form-item label="规格" :prop="'detailInfos[' + index + '].specification'">
                        <u--input v-model="inputForm.detailInfos[index].specification" disabled></u--input>
                    </u-form-item>
                    <u-form-item label="单位" :prop="'detailInfos[' + index + '].company'">
                        <u--input v-model="inputForm.detailInfos[index].company" disabled></u--input>
                    </u-form-item>
                    <u-form-item label="入库批次" :prop="'detailInfos[' + index + '].wareHouseNumber'">
                        <u--input v-model="inputForm.detailInfos[index].wareHouseNumber" disabled></u--input>
                    </u-form-item>
                    <u-form-item label="入库日期" :prop="'detailInfos[' + index + '].wareHouseDate'">
                        <u--input :value="formatDisplayDate(inputForm.detailInfos[index].wareHouseDate)" disabled>
                        </u--input>
                    </u-form-item>
                    <u-form-item label="批次库存" :prop="'detailInfos[' + index + '].surplusNumber'">
                        <u--input v-model="inputForm.detailInfos[index].surplusNumber" disabled></u--input>
                    </u-form-item>
                    <u-form-item label="报损数量" :prop="'detailInfos[' + index + '].lossNumber'" :required="true">
                        <u--input v-model="inputForm.detailInfos[index].lossNumber" placeholder="请输入报损数量"
                            :disabled="nodeFlag" @blur="handleLossNumberBlur(index)"></u--input>
                    </u-form-item>
                    <u-form-item label="报损原因" :prop="'detailInfos[' + index + '].lossReason'" :required="true">
                        <u--textarea v-model="inputForm.detailInfos[index].lossReason" placeholder="请输入报损原因"
                            :disabled="nodeFlag" :rows="3" :maxlength="200"></u--textarea>
                    </u-form-item>
                    <u-form-item label="附件上传">
                        <UploadComponent :uploadUrl="`${uploadUrl}/public-modules-server/oss/file/webUpload/upload`"
                            @onRemove="(file, fileList, fileIndex) => handleRemove(file, fileList, index, fileIndex, 'detail')"
                            @onSuccess="(file, fileList) => handleUploadSuccess(file, fileList, index, 'detail')"
                            :fileList="inputForm.detailInfos[index].fileInfoLost" :limit="3" :isDelete="nodeFlag"
                            :isUpload="nodeFlag">
                        </UploadComponent>
                    </u-form-item>

                    <u-form-item label="" v-if="!nodeFlag">
                        <el-button style="width: 100%" type="danger" plain @click="removeDetail(index)">
                            删除报损详情
                        </el-button>
                    </u-form-item>
                </view>

                <u-form-item label="" v-if="!nodeFlag">
                    <el-button style="width: 100%" type="primary" @click="addDetail()" plain>新增报损详情</el-button>
                </u-form-item>
            </view>

            <u-form-item label="附件">
                <UploadComponent :uploadUrl="`${uploadUrl}/public-modules-server/oss/file/webUpload/upload`"
                    @onRemove="(file, fileList, fileIndex) => handleRemove(file, fileList, '', fileIndex, '')"
                    @onSuccess="(file, fileList) => handleUploadSuccess(file, fileList, '', '')"
                    :fileList="inputForm.files" :limit="3" :isDelete="nodeFlag" :isUpload="nodeFlag">
                </UploadComponent>
            </u-form-item>
        </u--form>

        <user-select ref="userPicker" @input="handleUserSelected"></user-select>
        <ba-tree-picker ref="treePicker" :multiple="false" @select-change="selectTypeChange" title="类型选择"
            :localdata="listData" valueKey="value" textKey="label" childrenKey="children" />
    </view>
</template>

<script>
import { mapState } from 'vuex'
import userSelect from '@/components/user-select/user-select-radio.vue'
import baTreePicker from '@/components/ba-tree-picker/ba-tree-picker.vue'
import UploadComponent from '@/pages/common/UploadComponent.vue'
import upload from '@/utils/upload.js'
import MaterialTypeService from '@/api/psi/MaterialTypeService'
import WareHouseService from '@/api/psi/WareHouseService'
import LossService from '@/api/psi/LossService'
import CommonApi from '@/api/common/CommonApi'
import LossGoodsSelector from './LossGoodsSelector.vue'

export default {
    name: 'PsiLossForm',
    components: {
        userSelect,
        baTreePicker,
        UploadComponent,
        LossGoodsSelector
    },
    computed: mapState({
        userInfo: (state) => state.user.userInfo
    }),
    props: {
        businessId: {
            type: String,
            default: ''
        },
        formReadOnly: {
            type: Boolean,
            default: false
        },
        status: {
            type: String,
            default: ''
        },
        isCc: {
            type: Boolean,
            default: false
        }
    },
    data() {
        return {
            uploadUrl: upload.UPLOAD_URL,
            nodeFlag: false,
            loading: false,
            listData: [],
            materialList: [],
            inputForm: this.createInputForm(),
            rules: {
                lossDate: [
                    {
                        required: true,
                        message: '报损时间不能为空',
                        trigger: ['change']
                    }
                ]
            }
        }
    },
    materialTypeService: null,
    wareHouseService: null,
    lossService: null,
    commonApi: null,
    created() {
        this.ensureServices()
        this.loadMaterialTypes()
        this.fillUserInfo()
    },
    watch: {
        businessId: {
            handler() {
                if (this.businessId) {
                    this.init(this.businessId)
                } else {
                    this.resetForm()
                    this.nodeFlag = this.formReadOnly || this.status === 'taskFormDetail' || this.status === 'testSee'
                }
            },
            immediate: true,
            deep: false
        }
    },
    methods: {
        createInputForm() {
            return {
                id: '',
                procInsId: '',
                processDefinitionId: '',
                status: '',
                lossNo: '',
                lossDate: '',
                remarks: '',
                handledBy: '',
                handledById: '',
                handledByOffice: '',
                handledByOfficeName: '',
                userId: '',
                files: [],
                detailInfos: []
            }
        },
        createDetailRow() {
            return {
                id: '',
                recipientAgent: (this.userInfo && this.userInfo.name) || '',
                recipientAgentId: (this.userInfo && this.userInfo.id) || '',
                recipientOffice: (this.userInfo && this.userInfo.officeDTO && this.userInfo.officeDTO.name) || '',
                collectType: '',
                collectTypeId: '',
                goodsName: '',
                inventoryId: '',
                lossNumber: '',
                lossReason: '',
                company: '',
                brand: '',
                specification: '',
                wareHouseNumber: '',
                wareHouseDate: '',
                produceDate: '',
                shelfLife: '',
                shelfLifeUnit: '',
                spec: '1',
                surplusNumber: '',
                currentInventory: '',
                fileInfoLost: []
            }
        },
        ensureServices() {
            if (!this.materialTypeService) {
                this.materialTypeService = new MaterialTypeService()
            }
            if (!this.wareHouseService) {
                this.wareHouseService = new WareHouseService()
            }
            if (!this.lossService) {
                this.lossService = new LossService()
            }
            if (!this.commonApi) {
                this.commonApi = new CommonApi()
            }
        },
        async loadMaterialTypes() {
            try {
                const data = await this.materialTypeService.cgList()
                this.materialList = data || []
                this.listData = this.buildTree(this.materialList)
            } catch (e) {
                this.materialList = []
                this.listData = []
            }
        },
        fillUserInfo() {
            if (!this.userInfo) {
                return
            }
            this.inputForm.handledBy = this.inputForm.handledBy || this.userInfo.name
            this.inputForm.handledById = this.inputForm.handledById || this.userInfo.id
            this.inputForm.userId = this.inputForm.userId || this.userInfo.id
            this.inputForm.handledByOffice = this.inputForm.handledByOffice || (this.userInfo.officeDTO && this.userInfo.officeDTO.id) || ''
            this.inputForm.handledByOfficeName = this.inputForm.handledByOfficeName || (this.userInfo.officeDTO && this.userInfo.officeDTO.name) || ''
        },
        resetForm() {
            this.inputForm = this.createInputForm()
            this.fillUserInfo()
        },
        async init(id) {
            this.ensureServices()
            this.resetForm()
            this.inputForm.id = id
            this.loading = true
            try {
                const data = await this.lossService.findById(id)
                this.inputForm = this.normalizeFormData(this.recover(this.createInputForm(), data))
                this.fillUserInfo()
                this.nodeFlag = await this.resolveNodeFlag(data)
            } catch (e) {
                this.nodeFlag = true
            } finally {
                this.loading = false
            }
        },
        async resolveNodeFlag(data) {
            if (this.formReadOnly || this.status === 'taskFormDetail' || this.status === 'testSee') {
                return true
            }
            try {
                const taskName = await this.commonApi.getTaskNameByProcInsId((data && data.procInsId) || this.inputForm.procInsId)
                if (this.isNotEmpty(taskName)) {
                    return taskName !== '发起人重新发起申请'
                }
            } catch (e) {
            }
            return false
        },
        normalizeFormData(data) {
            const form = data || this.createInputForm()
            if (this.isNotEmpty(form.lossDate)) {
                form.lossDate = new Date(form.lossDate)
            }
            form.files = form.files || []
            form.detailInfos = (form.detailInfos || []).map(item => ({
                ...item,
                fileInfoLost: item.fileInfoLost || [],
                produceDate: this.isNotEmpty(item.produceDate) ? new Date(item.produceDate) : '',
                surplusNumber: this.isNotEmpty(item.surplusNumber) ? this.formatNumber(item.surplusNumber) : ''
            }))
            return form
        },
        buildTree(nodes, parentId = '0') {
            const tree = []
            for (const node of nodes || []) {
                if (node.parentId === parentId) {
                    const children = this.buildTree(nodes, node.id)
                    if (children.length) {
                        node.children = children
                    }
                    tree.push(node)
                }
            }
            return tree
        },
        isEmpty(value) {
            if (value === null || value === undefined) {
                return true
            }
            if (typeof value === 'string' && value.trim() === '') {
                return true
            }
            if (Array.isArray(value) && value.length === 0) {
                return true
            }
            return false
        },
        isNotEmpty(value) {
            return !this.isEmpty(value)
        },
        formatDate(date) {
            if (this.isEmpty(date)) {
                return ''
            }
            const dateValue = new Date(date)
            if (Number.isNaN(dateValue.getTime())) {
                return ''
            }
            const year = dateValue.getFullYear()
            const month = `${dateValue.getMonth() + 1}`.padStart(2, '0')
            const day = `${dateValue.getDate()}`.padStart(2, '0')
            return `${year}-${month}-${day}`
        },
        formatDisplayDate(date) {
            return this.formatDate(date)
        },
        normalizeDateFieldsBeforeValidate() {
            if (this.isNotEmpty(this.inputForm.lossDate)) {
                this.inputForm.lossDate = this.formatDate(this.inputForm.lossDate)
            }
        },
        formatNumber(value) {
            const numberValue = Number(value || 0)
            if (Number.isNaN(numberValue)) {
                return ''
            }
            return numberValue % 1 === 0 ? String(numberValue) : numberValue.toFixed(2).replace(/\.?0+$/, '')
        },
        formatBatchStock(currentInventory, spec) {
            const current = Number(currentInventory || 0)
            const specNumber = Number(spec || 1)
            if (Number.isNaN(current) || Number.isNaN(specNumber)) {
                return '0'
            }
            return this.formatNumber(current * (specNumber > 0 ? specNumber : 1))
        },
        formatNumberInput(inputValue, decimalLimit = 2) {
            if (this.isEmpty(inputValue)) {
                return ''
            }
            const valueText = String(inputValue)
            if (!/^\d*\.?\d*$/.test(valueText)) {
                return ''
            }
            let value = valueText.replace(/[^\d.]/g, '')
            const dotIndex = value.indexOf('.')
            if (dotIndex !== -1) {
                const substr = value.substr(dotIndex + 1)
                if (substr.indexOf('.') !== -1) {
                    value = value.substr(0, dotIndex + 1) + substr.replace(/\./g, '')
                }
            }
            if (dotIndex !== -1) {
                const integerPart = value.substring(0, dotIndex)
                const decimalPart = value.substring(dotIndex + 1, dotIndex + 1 + decimalLimit)
                value = integerPart + '.' + decimalPart
            }
            return value
        },
        addDetail() {
            this.inputForm.detailInfos.push(this.createDetailRow())
        },
        removeDetail(index) {
            this.inputForm.detailInfos.splice(index, 1)
        },
        patchDetail(index, patch) {
            const detail = (this.inputForm.detailInfos || [])[index] || {}
            this.$set(this.inputForm.detailInfos, index, {
                ...detail,
                ...patch
            })
        },
        openUserPullForm(index) {
            if (this.nodeFlag) {
                return
            }
            this.$refs.userPicker.open(index, 'detail')
        },
        handleUserSelected(data, index, type) {
            if (type !== 'detail') {
                return
            }
            this.patchDetail(index, {
                recipientAgentId: data.id,
                recipientAgent: data.label,
                recipientOffice: data.parentLabel
            })
        },
        openTypePicker(index) {
            if (this.nodeFlag) {
                return
            }
            this.$refs.treePicker._show(index)
        },
        selectTypeChange(ids, names, index) {
            this.patchDetail(index, {
                collectType: names,
                collectTypeId: ids[0],
                goodsName: '',
                inventoryId: '',
                company: '',
                brand: '',
                specification: '',
                wareHouseNumber: '',
                wareHouseDate: '',
                produceDate: '',
                shelfLife: '',
                shelfLifeUnit: '',
                spec: '1',
                surplusNumber: '',
                currentInventory: '',
                lossNumber: ''
            })
        },
        async handleGoodsSelected({ index, item }) {
            const stock = this.formatBatchStock(item.currentInventory, item.spec)
            this.patchDetail(index, {
                inventoryId: item.id || '',
                collectType: item.tradeName || '',
                collectTypeId: item.wareHouseType || '',
                goodsName: item.tradeName || '',
                company: item.company || '',
                brand: item.brand || '',
                specification: item.specification || '',
                wareHouseNumber: item.wareHouseNumber || '',
                wareHouseDate: this.isNotEmpty(item.wareHouseDate) ? new Date(item.wareHouseDate) : '',
                produceDate: this.isNotEmpty(item.produceDate) ? new Date(item.produceDate) : '',
                shelfLife: item.shelfLife || '',
                shelfLifeUnit: item.shelfLifeUnit || '',
                spec: item.spec || '1',
                currentInventory: item.currentInventory || '',
                surplusNumber: stock
            })
        },
        async syncDetailStock(index) {
            const detail = (this.inputForm.detailInfos || [])[index]
            if (!detail || this.isEmpty(detail.goodsName) || this.isEmpty(detail.collectTypeId)) {
                return
            }
            try {
                const data = await this.wareHouseService.getByProduceDateNotMerge({
                    current: 1,
                    size: 1000,
                    tradeName: detail.goodsName,
                    wareHouseType: detail.collectTypeId
                })
                const records = (data && data.records) || []
                const total = records.reduce((sum, item) => {
                    const currentInventory = Number(item.currentInventory || 0)
                    const spec = Number(item.spec || 1)
                    return sum + currentInventory * (spec > 0 ? spec : 1)
                }, 0)
                this.$set(this.inputForm.detailInfos[index], 'surplusNumber', this.formatNumber(total))
            } catch (e) {
                this.$set(this.inputForm.detailInfos[index], 'surplusNumber', '')
                uni.showToast({
                    title: '库存数量加载失败',
                    icon: 'none'
                })
            }
        },
        handleUploadSuccess(file, fileList, index, type) {
            if (type === 'detail') {
                this.inputForm.detailInfos[index].fileInfoLost = fileList
            } else {
                this.inputForm.files = fileList
            }
        },
        handleRemove(file, fileList, lineIndex, fileIndex, type) {
            if (type === 'detail') {
                this.inputForm.detailInfos[lineIndex].fileInfoLost.splice(fileIndex, 1)
            } else {
                this.inputForm.files.splice(fileIndex, 1)
            }
        },
        handleLossNumberBlur(index) {
            const detail = (this.inputForm.detailInfos || [])[index]
            if (!detail) {
                return
            }
            detail.lossNumber = this.formatNumberInput(detail.lossNumber)
            if (this.isNotEmpty(detail.surplusNumber) && this.isNotEmpty(detail.lossNumber) &&
                Number(detail.lossNumber) > Number(detail.surplusNumber)) {
                this.$message.error('报损数量不能大于当前库存')
                detail.lossNumber = ''
            }
        },
        validateDetailInfos(checkStock = true) {
            if (this.isEmpty(this.inputForm.detailInfos)) {
                this.$message.error('请填写报损明细')
                return false
            }
            for (let index = 0; index < this.inputForm.detailInfos.length; index++) {
                const detail = this.inputForm.detailInfos[index]
                const lineNo = index + 1
                if (this.isEmpty(detail.recipientAgentId)) {
                    this.$message.error(`报损明细第${lineNo}行请选择报损人`)
                    return false
                }
                if (this.isEmpty(detail.collectTypeId)) {
                    this.$message.error(`报损明细第${lineNo}行请选择报损类型`)
                    return false
                }
                if (this.isEmpty(detail.goodsName)) {
                    this.$message.error(`报损明细第${lineNo}行请选择物品名称`)
                    return false
                }
                if (this.isEmpty(detail.inventoryId)) {
                    this.$message.error(`报损明细第${lineNo}行请选择报损库存批次`)
                    return false
                }
                if (this.isEmpty(detail.lossNumber)) {
                    this.$message.error(`报损明细第${lineNo}行请输入报损数量`)
                    return false
                }
                if (this.isEmpty(detail.lossReason)) {
                    this.$message.error(`报损明细第${lineNo}行请输入报损原因`)
                    return false
                }
                if (checkStock && this.isNotEmpty(detail.surplusNumber) && Number(detail.lossNumber) > Number(detail.surplusNumber)) {
                    this.$message.error(`报损明细第${lineNo}行报损数量不能大于当前库存`)
                    return false
                }
            }
            return true
        },
        toSubmitData() {
            const data = JSON.parse(JSON.stringify(this.inputForm))
            data.lossDate = this.formatDate(this.inputForm.lossDate)
            data.detailInfos = (this.inputForm.detailInfos || []).map(item => ({
                ...JSON.parse(JSON.stringify(item)),
                produceDate: this.formatDate(item.produceDate)
            }))
            return data
        },
        async saveForm(callback) {
            this.loading = true
            try {
                const submitData = this.toSubmitData()
                submitData.status = '1'
                this.inputForm.status = '1'
                const data = await this.lossService.save(submitData)
                callback(data.businessTable, data.businessId, submitData)
            } finally {
                this.loading = false
            }
        },
        async startForm(callback) {
            this.loading = true
            try {
                if (this.isNotEmpty(this.inputForm.id)) {
                    const data = await this.lossService.findById(this.inputForm.id)
                    if (this.isNotEmpty(data.status) && !['0', '1', '3'].includes(data.status)) {
                        this.$message.error('任务数据已发生改变或不存在，请在待办任务中确认此任务是否存在')
                        throw new Error('invalid status')
                    }
                }
                await this.startFormTrue(callback)
            } finally {
                this.loading = false
            }
        },
        async startFormTrue(callback) {
            this.normalizeDateFieldsBeforeValidate()
            await this.$refs.inputForm.validate()
            if (!this.validateDetailInfos(true)) {
                return
            }
            const submitData = this.toSubmitData()
            submitData.status = '2'
            this.inputForm.status = '2'
            const data = await this.lossService.save(submitData)
            this.inputForm.id = data.businessId
            callback(data.businessTable, data.businessId, submitData)
        },
        async reapplyForm(callback) {
            this.loading = true
            try {
                const data = await this.lossService.findById(this.inputForm.id)
                if (data.status !== '4') {
                    this.$message.error('任务数据已发生改变或不存在，请在待办任务中确认此任务是否存在')
                    throw new Error('invalid status')
                }
                await this.startFormTrue(callback)
            } finally {
                this.loading = false
            }
        },
        async agreeForm(callback) {
            this.loading = true
            try {
                this.normalizeDateFieldsBeforeValidate()
                await this.$refs.inputForm.validate()
                if (!this.validateDetailInfos(false)) {
                    return
                }
                const submitData = this.toSubmitData()
                submitData.status = '5'
                this.inputForm.status = '5'
                const data = await this.lossService.save(submitData)
                callback(data.businessTable, data.businessId, submitData)
            } finally {
                this.loading = false
            }
        },
        async updateStatusById(type, callback) {
            this.loading = true
            try {
                if (type === 'reject' || type === 'reback') {
                    const data = await this.lossService.findById(this.inputForm.id)
                    if (data.status !== '2') {
                        this.$message.error('任务数据已发生改变或不存在，请在待办任务中确认此任务是否存在')
                        throw new Error('invalid status')
                    }
                    const nextStatus = type === 'reject' ? '4' : '3'
                    this.inputForm.status = nextStatus
                    await this.lossService.updateStatusById({
                        status: nextStatus,
                        id: this.inputForm.id
                    })
                    callback()
                } else if (type === 'hold') {
                    const data = await this.lossService.findById(this.inputForm.id)
                    if (data.status !== '4') {
                        this.$message.error('任务数据已发生改变或不存在，请在待办任务中确认此任务是否存在')
                        throw new Error('invalid status')
                    }
                    this.inputForm.status = '1'
                    await this.lossService.updateStatusById({
                        status: '1',
                        id: this.inputForm.id
                    })
                    callback()
                }
            } finally {
                this.loading = false
            }
        }
    }
}
</script>

<style scoped>
.section-wrap {
    margin-top: 24rpx;
}

.section-title {
    margin-bottom: 8rpx;
    padding-left: 8rpx;
    font-size: 30rpx;
    font-weight: 700;
    color: #1f2937;
    border-left: 6rpx solid #2979ff;
}

.section-tip {
    margin-bottom: 16rpx;
    font-size: 24rpx;
    color: #64748b;
}

.detail-card {
    margin-bottom: 20rpx;
    padding: 24rpx;
    background: #fff;
    border-radius: 20rpx;
    box-shadow: 0 10rpx 30rpx rgba(15, 23, 42, 0.05);
}

.detail-card-title {
    margin-bottom: 12rpx;
    font-size: 28rpx;
    font-weight: 600;
    color: #0f172a;
}
</style>
