package com.maintain.business.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.maintain.business.domain.ErpRepairForm;
import com.maintain.business.domain.ErpSettlementMaintain;
import com.maintain.business.domain.ErpSettlementMaintainRepairForm;
import com.maintain.business.domain.bo.ErpSettlementMaintainBo;
import com.maintain.business.domain.bo.ErpSettlementMaintainPayBo;
import com.maintain.business.domain.vo.ErpClientVo;
import com.maintain.business.domain.vo.ErpSettlementMaintainVo;
import com.maintain.business.mapper.ErpClientMapper;
import com.maintain.business.mapper.ErpRepairFormMapper;
import com.maintain.business.mapper.ErpSettlementMaintainMapper;
import com.maintain.business.mapper.ErpSettlementMaintainRepairFormMapper;
import com.maintain.business.service.IErpSettlementMaintainService;
import com.maintain.common.core.domain.PageQuery;
import com.maintain.common.core.domain.entity.SysDept;
import com.maintain.common.core.page.TableDataInfo;
import com.maintain.common.enums.RepairFormSettlementState;
import com.maintain.common.enums.SettlementState;
import com.maintain.common.exception.ServiceException;
import com.maintain.common.helper.LoginHelper;
import com.maintain.common.pay.PayResponse;
import com.maintain.common.pay.YinLianPayApi;
import com.maintain.common.utils.StringUtils;
import com.maintain.common.utils.redis.RedisUtils;
import com.maintain.system.mapper.SysDeptMapper;
import lombok.RequiredArgsConstructor;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 结算维修单Service业务层处理
 *
 * @author liushuai
 * @date 2025-04-03
 */
@RequiredArgsConstructor
@Service
public class ErpSettlementMaintainServiceImpl implements IErpSettlementMaintainService {

    private final ErpSettlementMaintainMapper baseMapper;
    private final ErpSettlementMaintainRepairFormMapper settlementMaintainRepairFormMapper;
    private final ErpRepairFormMapper repairFormMapper;
    private final ErpClientMapper clientMapper;
    private final YinLianPayApi yinLianPayApi;
    private final SysDeptMapper sysDeptMapper;
    @Value("${pay.merchantCode}")
    private String merchantCode;

    /**
     * 查询结算维修单
     */
    @Override
    public ErpSettlementMaintainVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    /**
     * 查询结算维修单列表
     */
    @Override
    public TableDataInfo<ErpSettlementMaintainVo> queryPageList(ErpSettlementMaintainBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<ErpSettlementMaintain> lqw = buildQueryWrapper(bo);
        Page<ErpSettlementMaintainVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    /**
     * 查询结算维修单列表
     */
    @Override
    public List<ErpSettlementMaintainVo> queryList(ErpSettlementMaintainBo bo) {
        LambdaQueryWrapper<ErpSettlementMaintain> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<ErpSettlementMaintain> buildQueryWrapper(ErpSettlementMaintainBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<ErpSettlementMaintain> lqw = Wrappers.lambdaQuery();
        lqw.like(StringUtils.isNotBlank(bo.getSettlementNumber()), ErpSettlementMaintain::getSettlementNumber, bo.getSettlementNumber());
        lqw.eq(bo.getClientId() != null, ErpSettlementMaintain::getClientId, bo.getClientId());
        lqw.like(StringUtils.isNotBlank(bo.getClientName()), ErpSettlementMaintain::getClientName, bo.getClientName());
        lqw.like(StringUtils.isNotBlank(bo.getClientPhone()), ErpSettlementMaintain::getClientPhone, bo.getClientPhone());
        lqw.eq(bo.getClientType() != null, ErpSettlementMaintain::getClientType, bo.getClientType());
        lqw.eq(bo.getClientCertificateType() != null, ErpSettlementMaintain::getClientCertificateType, bo.getClientCertificateType());
        lqw.eq(StringUtils.isNotBlank(bo.getClientCertificateNumber()), ErpSettlementMaintain::getClientCertificateNumber, bo.getClientCertificateNumber());
        lqw.eq(bo.getState() != null, ErpSettlementMaintain::getState, bo.getState());
        lqw.eq(bo.getCreateDeptId() != null, ErpSettlementMaintain::getCreateDeptId, bo.getCreateDeptId());
        lqw.orderByDesc(ErpSettlementMaintain::getCreateTime);
        return lqw;
    }

    /**
     * 新增结算维修单
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean insertByBo(ErpSettlementMaintainBo bo) {
        ErpClientVo clientVo = clientMapper.selectVoById(bo.getClientId());
        ErpSettlementMaintain add = BeanUtil.toBean(bo, ErpSettlementMaintain.class);
        validEntityBeforeSave(add);
        add.setClientName(clientVo.getName());
        add.setClientPhone(clientVo.getPhone());
        add.setClientType(clientVo.getType());
        add.setClientCertificateType(clientVo.getCertificateType());
        add.setClientCertificateNumber(clientVo.getCertificateNumber());
        add.setSettlementNumber(RedisUtils.generateNextNumber("BXJS"));
        add.setCreateDeptId(LoginHelper.getDeptId());
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            settlementMaintainRepairFormMapper.insertBatch(
                bo.getRepairFormIds().stream().map(item -> {
                ErpSettlementMaintainRepairForm repairForm = new ErpSettlementMaintainRepairForm();
                repairForm.setRepairFormId(item);
                repairForm.setSettlementMaintainId(add.getId());
                return repairForm;
            }).collect(Collectors.toList()));
            repairFormMapper.updateBatchById(bo.getRepairFormIds().stream().map(item ->{
                ErpRepairForm repairForm = new ErpRepairForm();
                repairForm.setId(item);
                repairForm.setSettlementTime(new Date());
                repairForm.setSettlementState(RepairFormSettlementState.TWO.getCode());
                return repairForm;
            }).collect(Collectors.toList()));
        }
        return flag;
    }

    /**
     * 修改结算维修单
     */
    @Override
    public Boolean updateByBo(ErpSettlementMaintainBo bo) {
        ErpSettlementMaintain update = BeanUtil.toBean(bo, ErpSettlementMaintain.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 保存前的数据校验
     */
    private void validEntityBeforeSave(ErpSettlementMaintain entity){
        //TODO 做一些数据校验,如唯一约束
    }

    /**
     * 批量删除结算维修单
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        boolean flag = baseMapper.deleteBatchIds(ids) > 0;
        if (flag) {
            // 查出所有关联的报修单
            LambdaQueryWrapper<ErpSettlementMaintainRepairForm> lqw = Wrappers.lambdaQuery();
            lqw.in(ErpSettlementMaintainRepairForm::getSettlementMaintainId, ids);
            List<ErpSettlementMaintainRepairForm> repairFormList = settlementMaintainRepairFormMapper.selectList(lqw);

            // 关联的报修单状态更改至待结算
            LambdaUpdateWrapper<ErpRepairForm> luw = Wrappers.lambdaUpdate();
            luw.in(ErpRepairForm::getId, repairFormList.stream().map(ErpSettlementMaintainRepairForm::getRepairFormId).collect(Collectors.toList()))
                .set(ErpRepairForm::getSettlementState, RepairFormSettlementState.ONE.getCode());
            repairFormMapper.update(luw);
            // 删除结算单与报修单关联关系表数据
            settlementMaintainRepairFormMapper.deleteBatchIds(repairFormList.stream().map(ErpSettlementMaintainRepairForm::getId).collect(Collectors.toList()));
        }
        return flag;
    }

    /**
     * 结算维修单回执
     *
     * @param bo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean receiptByBo(ErpSettlementMaintainBo bo) {
        ErpSettlementMaintain settlementMaintain = baseMapper.selectById(bo.getId());
        settlementMaintain.setCollectionTime(bo.getCollectionTime());
        settlementMaintain.setCollectionVoucher(bo.getCollectionVoucher());
        settlementMaintain.setCollectionAccount(bo.getCollectionAccount());
        settlementMaintain.setCollectionSerialNumber(bo.getCollectionSerialNumber());
        settlementMaintain.setCollectionRemark(bo.getCollectionRemark());
        settlementMaintain.setState(SettlementState.TWO.getCode());
        boolean flag = baseMapper.updateById(settlementMaintain) > 0;
        if (flag) {
            // 查出所有关联的报修单
            LambdaQueryWrapper<ErpSettlementMaintainRepairForm> lqw = Wrappers.lambdaQuery();
            lqw.eq(ErpSettlementMaintainRepairForm::getSettlementMaintainId, settlementMaintain.getId());
            List<ErpSettlementMaintainRepairForm> repairFormList = settlementMaintainRepairFormMapper.selectList(lqw);

            // 关联的报修单状态更改至待结算
            LambdaUpdateWrapper<ErpRepairForm> luw = Wrappers.lambdaUpdate();
            luw.in(ErpRepairForm::getId, repairFormList.stream().map(ErpSettlementMaintainRepairForm::getRepairFormId).collect(Collectors.toList()))
                .set(ErpRepairForm::getSettlementState, RepairFormSettlementState.THREE.getCode());
            repairFormMapper.update(luw);
        }
        return flag;
    }

    /**
     * 结算维修单支付
     *
     * @param bo
     * @return
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public Boolean pay(ErpSettlementMaintainPayBo bo) {
        ErpSettlementMaintain maintain = baseMapper.selectById(bo.getId());
        List<ErpSettlementMaintainRepairForm> maintainRepairForms = settlementMaintainRepairFormMapper.selectList(
            new LambdaQueryWrapper<ErpSettlementMaintainRepairForm>()
                .eq(ErpSettlementMaintainRepairForm::getSettlementMaintainId, maintain.getId())
        );
        if (ObjectUtil.isEmpty(maintainRepairForms)) {
            throw new ServiceException("当前结算单未绑定维修单，请检查后重试！");
        }
        ErpSettlementMaintainRepairForm settlementMaintainRepairForm = maintainRepairForms.get(0);
        ErpRepairForm repairForm = repairFormMapper.selectById(settlementMaintainRepairForm.getRepairFormId());
        if (ObjectUtil.isEmpty(repairForm)) {
            throw new ServiceException("报修单不存在，请联系管理员！");
        }
        SysDept sysDept = sysDeptMapper.selectById(repairForm.getRepairerDeptId());
        if (ObjectUtil.isEmpty(sysDept)) {
            throw new ServiceException("维修车间不存在，请联系管理员！");
        }
        if (ObjectUtil.isEmpty(sysDept.getTerminalCode())) {
            throw new ServiceException("当前车间未填写终端号，请联系管理员添加！");
        }
        if (ObjectUtil.isEmpty(maintain)) {
            throw new ServiceException("当前支付订单不存在，请刷新后重试！");
        }
        if (maintain.getState().equals(SettlementState.TWO.getCode())) {
            throw new ServiceException("当前结算单已支付，不能重复支付！");
        }
        // 生成一个时间戳单号
        String orderNo = String.valueOf(System.currentTimeMillis());
        int money = maintain.getPracticalMoney().movePointRight(2).intValue();
        if (money == 0) {
            throw new ServiceException("结算单金额为0，无需支付！");
        }
        PayResponse response = yinLianPayApi.pay(orderNo, money, bo.getPaymentAccount(), sysDept.getTerminalCode());
        if (!response.getErrCode().equals("00")) {
            throw new ServiceException("结算单支付失败："+ response.getErrInfo());
        }
        maintain.setCollectionAccount(merchantCode);
        maintain.setCollectionSerialNumber(response.getOrderId());
        maintain.setCollectionTime(new Date());
        maintain.setState(SettlementState.TWO.getCode());
        maintain.setPaymentMethod(1);
        maintain.setPaymentAccount(bo.getPaymentAccount());
        maintain.setPaymentNumber(orderNo);
        baseMapper.updateById(maintain);
        return true;
    }
}
