package org.dromara.work.service.impl;

import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.yulichang.base.MPJBaseServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import lombok.RequiredArgsConstructor;
import org.dromara.common.core.domain.model.LoginUser;
import org.dromara.common.core.exception.ServiceException;
import org.dromara.common.core.utils.MapstructUtils;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.satoken.utils.LoginHelper;
import org.dromara.system.domain.SysUser;
import org.dromara.work.domain.TpClient;
import org.dromara.work.domain.TpClientStaff;
import org.dromara.work.domain.TpReceipt;
import org.dromara.work.domain.bo.TpReceiptBo;
import org.dromara.work.domain.vo.ReceiptSumVo;
import org.dromara.work.domain.vo.TpReceiptVo;
import org.dromara.work.mapper.TpClientMapper;
import org.dromara.work.mapper.TpClientStaffMapper;
import org.dromara.work.mapper.TpReceiptMapper;
import org.dromara.work.service.ITpReceiptService;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.Collection;
import java.util.Date;
import java.util.List;
import java.util.Map;

/**
 * 收款管理Service业务层处理
 *
 * @author Maosw
 * @date 2024-08-12
 */
@RequiredArgsConstructor
@Service
public class TpReceiptServiceImpl extends MPJBaseServiceImpl<TpReceiptMapper,TpReceipt> implements ITpReceiptService {

    private final TpReceiptMapper baseMapper;

    private final TpClientMapper clientMapper;

    private final TpClientStaffMapper clientStaffMapper;

    /**
     * 查询收款管理
     *
     * @param id 主键
     * @return 收款管理
     */
    @Override
    public TpReceiptVo queryById(Long id){
        return baseMapper.selectVoById(id);
    }


    /**
     * 分页查询收款管理列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 收款管理分页列表
     */
    /*@Override
    public TableDataInfo<TpReceiptVo> queryPageList(TpReceiptBo bo, PageQuery pageQuery) {
        LambdaQueryWrapper<TpReceipt> lqw = buildQueryWrapper(bo);
        lqw.orderByDesc(TpReceipt::getId);
        IPage<TpReceiptVo> result = baseMapper.selectVoPage(pageQuery.build(), lqw);
        return TableDataInfo.build(result);
    }*/

    /**
     * 分页查询收款管理列表
     *
     * @param bo        查询条件
     * @param pageQuery 分页参数
     * @return 收款管理分页列表
     */
    @Override
    public TableDataInfo<TpReceiptVo> queryPageList(TpReceiptBo bo, PageQuery pageQuery) {
        //bo.setIsDel(1);
        //和Mybatis plus一致，MPJLambdaWrapper的泛型必须是主表的泛型，并且要用主表的Mapper来调用
        MPJLambdaWrapper<TpReceipt> wrapper = buildQueryMPJWrapper(bo)
            .selectAll(TpReceipt.class)
            .selectAs("r.real_name",TpReceiptVo::getRname)
            .selectAs("a.real_name",TpReceiptVo::getAddname)
            .selectAs(TpClient::getCode,TpReceiptVo::getKcode)
            .selectAs(TpClientStaff::getName,TpReceiptVo::getCname)
            .leftJoin(SysUser.class,"r", SysUser::getUserId, TpReceipt::getRid)
            .leftJoin(SysUser.class,"a", SysUser::getUserId, TpReceipt::getAddUser)
            .leftJoin(TpClientStaff.class, TpClientStaff::getId, TpReceipt::getCid)
            .leftJoin(TpClient.class, TpClient::getId, TpClientStaff::getKid)
            .orderByDesc(TpReceipt::getHkTime);

        //分页查询 （需要启用 mybatis plus 分页插件）
        IPage<TpReceiptVo> listPage = baseMapper.selectJoinPage(new Page<>(pageQuery.getPageNum(), pageQuery.getPageSize()), TpReceiptVo.class, wrapper);
        return TableDataInfo.build(listPage);
    }

    /**
     * 查询符合条件的收款管理列表
     *
     * @param bo 查询条件
     * @return 收款管理列表
     */
    @Override
    public List<TpReceiptVo> queryList(TpReceiptBo bo) {
        MPJLambdaWrapper<TpReceipt> wrapper = buildQueryMPJWrapper(bo)
            .selectAll(TpReceipt.class)
            .selectAs("r.real_name",TpReceiptVo::getRname)
            .selectAs("a.real_name",TpReceiptVo::getAddname)
            .selectAs(TpClient::getCode,TpReceiptVo::getKcode)
            .selectAs(TpClientStaff::getName,TpReceiptVo::getCname)
            .leftJoin(SysUser.class,"r", SysUser::getUserId, TpReceipt::getRid)
            .leftJoin(SysUser.class,"a", SysUser::getUserId, TpReceipt::getAddUser)
            .leftJoin(TpClientStaff.class, TpClientStaff::getId, TpReceipt::getCid)
            .leftJoin(TpClient.class, TpClient::getId, TpClientStaff::getKid)
            .orderByDesc(TpReceipt::getId);
        return baseMapper.selectJoinList(TpReceiptVo.class,wrapper);
    }

    private MPJLambdaWrapper<TpReceipt> buildQueryMPJWrapper(TpReceiptBo bo) {
        Map<String, Object> params = bo.getParams();
        MPJLambdaWrapper<TpReceipt> lqw = new MPJLambdaWrapper<>();
        lqw.eq(bo.getId() != null, TpReceipt::getId, bo.getId());
        lqw.like(StringUtils.isNotBlank(bo.getKcode()), TpClient::getCode, bo.getKcode());
        lqw.like(StringUtils.isNotBlank(bo.getCname()), TpClientStaff::getName, bo.getCname());
        lqw.like(StringUtils.isNotBlank(bo.getAddname()), "a.real_name", bo.getAddname());
        lqw.like(StringUtils.isNotBlank(bo.getRname()), "r.real_name", bo.getRname());
        lqw.eq(bo.getQid() != null, TpReceipt::getQid, bo.getQid());
        lqw.eq(bo.getState() != null, TpReceipt::getState, bo.getState());
        if(bo.getState() != null && bo.getState() == 1){
            lqw.eq(TpReceipt::getIsDel, 1);
        }
        lqw.eq(bo.getCid() != null, TpReceipt::getCid, bo.getCid());
        lqw.eq(bo.getRid() != null, TpReceipt::getRid, bo.getRid());
        lqw.eq(bo.getIsDel() != null, TpReceipt::getIsDel, bo.getIsDel());
        lqw.eq(bo.getAddTime() != null, TpReceipt::getAddTime, bo.getAddTime());
        lqw.eq(bo.getAddUser() != null, TpReceipt::getAddUser, bo.getAddUser());
        lqw.like(StringUtils.isNotBlank(bo.getRemark()), TpReceipt::getRemark, bo.getRemark());
        lqw.like(StringUtils.isNotBlank(bo.getReturnRemark()), TpReceipt::getReturnRemark, bo.getReturnRemark());
        lqw.eq(StringUtils.isNotBlank(bo.getOutTradeNo()), TpReceipt::getOutTradeNo, bo.getOutTradeNo());
        lqw.eq(StringUtils.isNotBlank(bo.getTradeNo()), TpReceipt::getTradeNo, bo.getTradeNo());
        lqw.between(params.get("hkBeginTime") != null && params.get("hkEndTime") != null,
            TpReceipt::getHkTime, params.get("hkBeginTime"), params.get("hkEndTime"));
        lqw.between(params.get("rlBeginTime") != null && params.get("rlEndTime") != null,
            TpReceipt::getRlTime, params.get("rlBeginTime"), params.get("rlEndTime"));
        return lqw;
    }

    /**
     * 新增收款管理
     *
     * @param bo 收款管理
     * @return 是否新增成功
     */
    @Override
    public Boolean insertByBo(TpReceiptBo bo) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        bo.setAddUser(loginUser.getUserId());
        TpReceipt add = MapstructUtils.convert(bo, TpReceipt.class);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 新增收款管理
     *
     * @param bo 收款管理
     * @return 是否新增成功
     */
    @Override
    public Boolean insertReceipt(TpReceiptBo bo) {
        bo.setAddUser(1L);
        TpReceipt add = MapstructUtils.convert(bo, TpReceipt.class);
        boolean flag = baseMapper.insert(add) > 0;
        if (flag) {
            bo.setId(add.getId());
        }
        return flag;
    }

    /**
     * 修改收款管理
     *
     * @param bo 收款管理
     * @return 是否修改成功
     */
    @Override
    public Boolean updateByBo(TpReceiptBo bo) {
        TpReceipt update = MapstructUtils.convert(bo, TpReceipt.class);
        return baseMapper.updateById(update) > 0;
    }

    /**
     * 校验并批量删除收款管理信息
     *
     * @param ids     待删除的主键集合
     * @param isValid 是否进行有效性校验
     * @return 是否删除成功
     */
    @Override
    public Boolean deleteWithValidByIds(Collection<Long> ids, Boolean isValid) {
        List<TpReceipt> list = baseMapper.selectByIds(ids);
        for (TpReceipt receipt : list) {
            if (receipt.getState() == 2) {
                throw new ServiceException("该笔汇款：" + receipt.getId() + "已认领，不能作废！");
            }
        }
        list.stream().forEach(f ->f.setIsDel(2));
        return baseMapper.updateBatchById(list);
    }

    /**
     * 汇款信息统计
     * @param bo
     * @return
     */
    @Override
    public ReceiptSumVo queryListSum(TpReceiptBo bo) {
//        bo.setIsDel(1);
        ReceiptSumVo receiptSumVo = new ReceiptSumVo();
        MPJLambdaWrapper<TpReceipt> lqw = buildQueryMPJWrapper(bo)
            .leftJoin(SysUser.class,"r", SysUser::getUserId, TpReceipt::getRid)
            .leftJoin(SysUser.class,"a", SysUser::getUserId, TpReceipt::getAddUser)
            .leftJoin(TpClientStaff.class, TpClientStaff::getId, TpReceipt::getCid)
            .leftJoin(TpClient.class, TpClient::getId, TpClientStaff::getKid)
            .orderByDesc(TpReceipt::getId);
        receiptSumVo.setHkzbCount(baseMapper.selectJoinCount(lqw));

        lqw.select(TpReceipt::getPrice,TpReceipt::getState);
        List<TpReceiptVo> list = baseMapper.selectJoinList(TpReceiptVo.class,lqw);

        BigDecimal hkzeSum = list.stream().map(f -> new BigDecimal(String.valueOf(f.getPrice()))).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal yrlzeSum = list.stream().filter(f ->f.getState() == 2).map(f -> new BigDecimal(String.valueOf(f.getPrice()))).reduce(BigDecimal.ZERO, BigDecimal::add);
        BigDecimal wrlzeSum = list.stream().filter(f ->f.getState() == 1).map(f -> new BigDecimal(String.valueOf(f.getPrice()))).reduce(BigDecimal.ZERO, BigDecimal::add);

        MPJLambdaWrapper<TpReceipt> lqw3 = buildQueryMPJWrapper(bo).eq(TpReceipt::getIsDel,2);
        lqw3.select(TpReceipt::getPrice)
        .leftJoin(SysUser.class,"r", SysUser::getUserId, TpReceipt::getRid)
        .leftJoin(SysUser.class,"a", SysUser::getUserId, TpReceipt::getAddUser)
        .leftJoin(TpClientStaff.class, TpClientStaff::getId, TpReceipt::getCid)
        .leftJoin(TpClient.class, TpClient::getId, TpClientStaff::getKid)
        .orderByDesc(TpReceipt::getId);
        BigDecimal zfzeSum = baseMapper.selectJoinList(TpReceiptVo.class,lqw3).stream().map(f -> new BigDecimal(String.valueOf(f.getPrice()))).reduce(BigDecimal.ZERO, BigDecimal::add);

        receiptSumVo.setHkzeSum(hkzeSum);
        receiptSumVo.setYrlzeSum(yrlzeSum);
        receiptSumVo.setWrlzeSum(wrlzeSum);
        receiptSumVo.setZfzeSum(zfzeSum);
        return receiptSumVo;
    }

    /**
     * 认领汇款
     * @param bo
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public int updateClaimByBo(TpReceiptBo bo) {
        LoginUser loginUser = LoginHelper.getLoginUser();

        TpClientStaff clientStaff = clientStaffMapper.selectById(bo.getCid());
        TpClient client = clientMapper.selectById(clientStaff.getKid());
        TpReceipt receipt = baseMapper.selectById(bo.getId());
        if(receipt.getIsDel() == 2){
            throw new ServiceException("该笔汇款：" + receipt.getId() + "已作废，不能认领！");
        }
        if(receipt.getState() == 2){
            throw new ServiceException("该笔汇款：" + receipt.getId() + "已认领，不能重复认领！");
        }
        receipt.setState(2);
        receipt.setCid(clientStaff.getId());
//        receipt.setCname(client.getName());
        receipt.setRid(loginUser.getUserId());
//        receipt.setRname(loginUser.getRealName());
        receipt.setRlTime(new Date());
        baseMapper.updateById(receipt);

        clientStaff.setYue(clientStaff.getYue().add(receipt.getPrice()));
        client.setYue(client.getYue().add(receipt.getPrice()));
        clientStaffMapper.updateById(clientStaff);
        return clientMapper.updateById(client);
    }

    /**
     * 回退汇款
     * @param bo
     * @return
     */
    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public int updateBackByBo(TpReceiptBo bo) {
        LoginUser loginUser = LoginHelper.getLoginUser();
        TpReceipt receipt = baseMapper.selectById(bo.getId());
        if(receipt.getIsDel() == 2){
            throw new ServiceException("该笔汇款：" + receipt.getId() + "已作废，不能回退！");
        }
        if(receipt.getState() == 1){
            throw new ServiceException("该笔汇款：" + receipt.getId() + "未认领，不能回退！");
        }
        TpClientStaff clientStaff = clientStaffMapper.selectById(receipt.getCid());

        BigDecimal yue = clientStaff.getYue().subtract(receipt.getPrice());
        if(yue.compareTo(BigDecimal.ZERO) < 0){
            throw new ServiceException("客户账户余额不足，请联系客服");
        }

        TpClient client = clientMapper.selectById(clientStaff.getKid());
        BigDecimal yue1 = client.getYue().subtract(receipt.getPrice());
        if(yue1.compareTo(BigDecimal.ZERO) < 0){
            throw new ServiceException("客户账户余额不足，请联系客服");
        }

        receipt.setState(1);
        receipt.setCid(null);
        receipt.setKname(null);
//        receipt.setCname(null);
        receipt.setRid(null);
//        receipt.setRname(null);
        receipt.setRlTime(null);
        receipt.setAddUser(loginUser.getUserId());
//        receipt.setAddname(loginUser.getRealName());
        receipt.setAddTime(new Date());
        baseMapper.updateById(receipt);

        clientStaff.setYue(yue);
        clientStaffMapper.updateById(clientStaff);

        client.setYue(yue1);
        return clientMapper.updateById(client);
    }
}
