package com.pusong.business.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.pusong.business.domain.*;
import com.pusong.business.domain.vo.PsContractInfoVo;
import com.pusong.business.domain.vo.PsRefundVo;
import com.pusong.business.enums.*;
import com.pusong.business.service.IPsApproverRecordService;
import com.pusong.business.service.approver.ApproverContainer;
import com.pusong.business.service.approver.ApproverService;
import com.pusong.common.core.exception.ServiceException;
import com.pusong.common.core.utils.MapstructUtils;
import com.pusong.common.core.utils.StringUtils;
import com.pusong.common.mybatis.core.page.TableDataInfo;
import com.pusong.common.mybatis.core.page.PageQuery;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.pusong.system.domain.vo.SysOssVo;
import com.pusong.system.service.ISysOssService;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import org.springframework.stereotype.Service;
import com.pusong.business.domain.bo.PsContractPayBo;
import com.pusong.business.domain.vo.PsContractPayVo;
import com.pusong.business.mapper.PsContractPayMapper;
import com.pusong.business.service.IPsContractPayService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;

/**
 * 合同回款记录Service业务层处理
 *
 * @author wls
 * @date 2024-08-01
 */
@RequiredArgsConstructor
@Service
public class PsContractPayServiceImpl implements IPsContractPayService {

    private final PsContractPayMapper baseMapper;
    private final ISysOssService ossService;
    @Resource
    private final ApproverContainer container;
    private final IPsApproverRecordService approverRecordService;
    /**
     * 查询合同回款记录列表
     *
     * @param contractCode        合同编码
     * @return
     */
    public List<PsContractPayVo> queryListByContractCode(String contractCode,String business,PayStatusEnum enu){
        if(StringUtils.isBlank(contractCode)){return new ArrayList<>();}
        String code = enu == null ? null :enu.getCode();
        List<PsContractPayVo> list = baseMapper.selectVoList(Wrappers.<PsContractPay>lambdaQuery().
                eq(PsContractPay::getContractCode, contractCode).eq(PsContractPay::getDelFlag,0)
                .eq(StringUtils.isNotBlank(business),PsContractPay::getBusinessType,business)
                .eq(code != null ,PsContractPay::getPayStatus, code)
                .notIn(PsContractPay::getPayStatus, PayStatusEnum.getStatus())//去掉无用的状态
                .orderByAsc(PsContractPay::getPayDate));
        return list == null?new ArrayList<>():list;
    }

    /**
     * 查询合同所有支付记录列表
     *
     * @param contractCode        合同编码
     * @return
     */
    public List<PsContractPayVo> queryAllListByContractCode(String contractCode){
        if(StringUtils.isBlank(contractCode)){return new ArrayList<>();}
        List<PsContractPayVo> list = baseMapper.selectVoList(Wrappers.<PsContractPay>lambdaQuery().
                eq(PsContractPay::getContractCode, contractCode).eq(PsContractPay::getDelFlag,0)
                .orderByAsc(PsContractPay::getPayDate));
        list = list == null?new ArrayList<>():list;
        list.forEach(item->{
            if(StringUtils.equals("2",item.getBusinessType()) &&  StringUtils.equals(PayStatusEnum.FILE.getCode(),item.getPayStatus())){
                item.setPayStatusDesc(approverRecordService.getLastFail(item.getId()+"",null,List.of(ApproverTypeEnum.RETURN.getCode())));
            }else if(StringUtils.equals("1",item.getBusinessType()) &&  StringUtils.equals(PayStatusEnum.FILE.getCode(),item.getPayStatus())){
                item.setPayStatusDesc(approverRecordService.getLastFail(item.getId()+"",null,List.of(ApproverTypeEnum.PAY.getCode())));
            }
        });
        return list;
    }

    /**
     * 添加支付记录
     *
     * @param payBo 支付信息
     * @return 是否新增成功
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void addPay(List<MultipartFile> files, PsContractPayBo payBo){
        PsContractPay pay = MapstructUtils.convert(payBo, PsContractPay.class);
        List<String> payCertifications = new ArrayList<>();
        for(MultipartFile file : files){
            SysOssVo vo = ossService.upload(file);
            payCertifications.add(vo.getOssId()+"");
        }
        pay.setPayCertification(StringUtils.join(payCertifications,","));
        pay.setPayStatus(PayStatusEnum.PAYING.getCode());
        baseMapper.insert(pay);
        //发起审批
        ApproverService service = container.getService(ApproverTypeEnum.PAY.getCode());
        service.apply(pay.getId()+"", pay.getContractCode(), payBo.getPayDesc(), pay.getMoney().setScale(2, RoundingMode.HALF_UP).toPlainString());
    }
    /**
     * 添加退款记录
     *
     * @param payBo 支付信息
     * @return 是否新增成功
     */
    @Transactional(rollbackFor = Exception.class)
    @Override
    public void returnPay(List<MultipartFile> files, PsContractPayBo payBo){
        PsContractPay pay = MapstructUtils.convert(payBo, PsContractPay.class);
        if(StringUtils.equals("4",payBo.getPayType()) && CollectionUtils.isEmpty(files)){
            throw new ServiceException("请上传对私二维码");
        }
        if(CollectionUtils.isNotEmpty(files)){
            List<String> payCertifications = new ArrayList<>();
            for(MultipartFile file : files){
                SysOssVo vo = ossService.upload(file);
                payCertifications.add(vo.getOssId()+"");
            }
            pay.setGathMain(StringUtils.join(payCertifications,","));
        }

        pay.setPayStatus(PayStatusEnum.PAYAPPO.getCode());
        baseMapper.insert(pay);
        //发起审批
        ApproverService service = container.getService(ApproverTypeEnum.RETURN.getCode());
        service.apply(pay.getId() + "", pay.getContractCode(), payBo.getPayDesc(), pay.getMoney().stripTrailingZeros().toPlainString());
    }
    /**
     * 根据主键id查询回款记录
     *
     * @param id 查询条件
     * @return 合同回款记录列表
     */
    @Override
    public PsContractPayVo queryById(Long id) {
        return baseMapper.selectVoById(id);
    }

    /**
     * 根据id修改合同回款记录
     *
     * @param pay 合同回款记录
     * @return 是否修改成功
     */
    @Override
    public Boolean updateById(PsContractPay pay) {
        return baseMapper.updateById(pay) > 0;
    }



    /**
     * 退款列表查询
     *
     * @return 合同回款记录列表
     */
    @Override
    public TableDataInfo<PsRefundVo> queryRefundList(String customManageName,String companyName,String mobile,String name,PageQuery pageQuery,String payStatus){
        QueryWrapper<PsContractPay> qw = new QueryWrapper<PsContractPay>().in("pay.pay_status", List.of(PayStatusEnum.PAYING.getCode(),PayStatusEnum.SUCCESS.getCode()))
                .eq(StringUtils.isNotBlank(payStatus), "pay.pay_status", payStatus)
                .exists(StringUtils.isNotBlank(customManageName),"select 1 from sys_user su where su.user_id = cus.custom_manager and su.nick_name like %"+customManageName+"%")
                .like(StringUtils.isNotBlank(companyName),"com.company_name",companyName)
                .like(StringUtils.isNotBlank(mobile),"cus.custom_mobile",mobile)
                .like(StringUtils.isNotBlank(name),"cus.custom_name",name)
                .in("pay.pay_status",List.of(PayStatusEnum.SUCCESS.getCode(),PayStatusEnum.PAYING.getCode()))
                .eq("pay.business_type","2");
        Page<PsRefundVo> list = baseMapper.queryRefundList(pageQuery.build(), qw);
        list.getRecords().forEach(info->{
            List<PsContractPayVo> payList = queryListByContractCode(info.getContractCode(),null,PayStatusEnum.SUCCESS);
            //退款金额
            BigDecimal returnMoney = payList.stream().filter(item -> StringUtils.equals(item.getBusinessType(), PayBuinessStatusEnum.RETURN.getCode()))
                    .map(PsContractPayVo::getMoney).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
            //收款金额
            BigDecimal netPay = payList.stream().filter(item -> StringUtils.equals(item.getBusinessType(), PayBuinessStatusEnum.PAY.getCode()))
                    .map(PsContractPayVo::getMoney).filter(Objects::nonNull).reduce(BigDecimal.ZERO, BigDecimal::add);
            BigDecimal pay = netPay.subtract(returnMoney);
            //已付金额(收款-退款)
            info.setPayMoney(pay.compareTo(BigDecimal.ZERO)>=0?pay:BigDecimal.ZERO);
        });
        return TableDataInfo.build(list);
    }

    /**
     * 完成退款
     * @param files 附件图片
     * @param id 任务id
     * @return
     */
    public String refundFinish(List<MultipartFile> files, Long id){
        PsContractPay info = baseMapper.selectById(id);
        List<String> payCertifications = new ArrayList<>();
        for(MultipartFile file : files){
            SysOssVo vo = ossService.upload(file);
            payCertifications.add(vo.getOssId()+"");
        }
        info.setPayDate(new Date());
        info.setPayCertification(StringUtils.join(payCertifications,","));
        info.setPayStatus(PayStatusEnum.SUCCESS.getCode());
        baseMapper.updateById(info);
        return info.getContractCode();
    }

  /*  *//**
     * 查询合同回款记录
     *
     * @param id 主键
     * @return 合同回款记录
     *//*
    @Override
    public PsContractPayVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }

    *//**
     * 分页查询合同回款记录列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 合同回款记录分页列表
     *//*
    @Override
    public TableDataInfo<PsContractPayVo> queryPageList(PsContractPayBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<PsContractPay> lqw = buildQueryWrapper(bo);
        Page<PsContractPayVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }

    *//**
     * 查询符合条件的合同回款记录列表
     *
     * @param bo 查询条件
     * @return 合同回款记录列表
     *//*
    @Override
    public List<PsContractPayVo> queryList(PsContractPayBo bo) {
        LambdaQueryWrapper<PsContractPay> lqw = buildQueryWrapper(bo);
        return baseMapper.selectVoList(lqw);
    }

    private LambdaQueryWrapper<PsContractPay> buildQueryWrapper(PsContractPayBo bo) {
        Map<String, Object> params = bo.getParams();
        LambdaQueryWrapper<PsContractPay> lqw = Wrappers.lambdaQuery();
        lqw.eq(bo.getContractId() != null, PsContractPay::getContractId, bo.getContractId());
        lqw.eq(bo.getMoney() != null, PsContractPay::getMoney, bo.getMoney());
        lqw.eq(bo.getPayDate() != null, PsContractPay::getPayDate, bo.getPayDate());
        lqw.eq(StringUtils.isNotBlank(bo.getPayType()), PsContractPay::getPayType, bo.getPayType());
        lqw.eq(StringUtils.isNotBlank(bo.getPayMode()), PsContractPay::getPayMode, bo.getPayMode());
        lqw.eq(StringUtils.isNotBlank(bo.getGathMain()), PsContractPay::getGathMain, bo.getGathMain());
        lqw.eq(StringUtils.isNotBlank(bo.getPayCertification()), PsContractPay::getPayCertification, bo.getPayCertification());
        lqw.eq(StringUtils.isNotBlank(bo.getPayDesc()), PsContractPay::getPayDesc, bo.getPayDesc());
        return lqw;
    }

    *//**
     * 新增合同回款记录
     *
     * @param bo 合同回款记录
     * @return 是否新增成功
     *//*
    @Override
    public Boolean insertByBo(PsContractPayBo bo) {
        PsContractPay add = MapstructUtils.convert(bo, PsContractPay.class);
        validEntityBeforeSave(add);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    *//**
     * 修改合同回款记录
     *
     * @param bo 合同回款记录
     * @return 是否修改成功
     *//*
    @Override
    public Boolean updateByBo(PsContractPayBo bo) {
        PsContractPay update = MapstructUtils.convert(bo, PsContractPay.class);
        validEntityBeforeSave(update);
        return baseMapper.updateById(update) > 0;
    }

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

    *//**
     * 校验并批量删除合同回款记录信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     *//*
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        if(isValid){
            //TODO 做一些业务上的校验,判断是否需要校验
        }
        return baseMapper.deleteBatchIds(ids) > 0;
    }*/
}
