package com.czg.service.order.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.bean.copier.CopyOptions;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Assert;
import cn.hutool.core.lang.Validator;
import cn.hutool.core.util.ArrayUtil;
import cn.hutool.core.util.NumberUtil;
import cn.hutool.core.util.StrUtil;
import com.czg.constants.SystemConstants;
import com.czg.exception.CzgException;
import com.czg.order.dto.CreditBuyerOrderDTO;
import com.czg.order.entity.CreditBuyer;
import com.czg.order.entity.CreditBuyerOrder;
import com.czg.order.entity.CreditPaymentRecord;
import com.czg.order.param.CreditBuyerOrderQueryParam;
import com.czg.order.param.CreditBuyerQueryParam;
import com.czg.order.param.CreditBuyerRepaymentParam;
import com.czg.order.service.CreditBuyerService;
import com.czg.order.vo.CreditBuyerRepaymentVo;
import com.czg.sa.StpKit;
import com.czg.service.order.mapper.CreditBuyerMapper;
import com.czg.service.order.mapper.CreditBuyerOrderMapper;
import com.czg.service.order.mapper.CreditPaymentRecordMapper;
import com.czg.utils.PageUtil;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Comparator;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 挂账人
 *
 * @author Tankaikai tankaikai@aliyun.com
 * @since 1.0 2025-03-04
 */
@Service
public class CreditBuyerServiceImpl extends ServiceImpl<CreditBuyerMapper, CreditBuyer> implements CreditBuyerService {

    @Resource
    private CreditPaymentRecordMapper creditPaymentRecordMapper;
    @Resource
    private CreditBuyerOrderMapper creditBuyerOrderMapper;

    @Override
    public Page<CreditBuyer> getCreditBuyerPage(CreditBuyerQueryParam param) {

        Long shopId = StpKit.USER.getShopId(0L);
        param.setShopId(shopId);
        QueryWrapper queryWrapper = query().eq(CreditBuyer::getShopId, shopId)
                .like(CreditBuyer::getMobile, param.getMobile())
                .like(CreditBuyer::getDebtor, param.getDebtor())
                .eq(CreditBuyer::getStatus, param.getStatus())
                .eq(CreditBuyer::getIsDel, SystemConstants.OneZero.ZERO);
        if (param.getRepaymentStatus() != null) {
            if (param.getRepaymentStatus() == 1) {
                queryWrapper.where(CreditBuyer::getAccountBalance).gt(CreditBuyer::getCreditAmount);
            } else {
                queryWrapper.where(CreditBuyer::getAccountBalance).le(CreditBuyer::getCreditAmount);
            }
        }
        return page(PageUtil.buildPage(), queryWrapper);
    }

    private void commonVerify(CreditBuyer dto) {
        try {
            Assert.notNull(dto.getShopId(), "{}({})不能为空", "店铺id", "shopId");
            Assert.notNull(dto.getStatus(), "{}({})不能为空", "状态", "status");
            Assert.notEmpty(dto.getDebtor(), "{}({})不能为空", "挂账人", "debtor");
            Assert.notEmpty(dto.getMobile(), "{}({})不能为空", "手机号", "mobile");
            Assert.notNull(dto.getCreditAmount(), "{}({})不能为空", "挂账额度", "creditAmount");
        } catch (IllegalArgumentException e) {
            throw new CzgException(e.getMessage());
        }
        if (!Validator.isMobile(dto.getMobile())) {
            throw new CzgException(StrUtil.format("{}({})不合法", "手机号", "mobile"));
        }
        if (NumberUtil.isLessOrEqual(dto.getCreditAmount(), BigDecimal.ZERO)) {
            throw new CzgException(StrUtil.format("{}({})必须大于0", "挂账额度", "creditAmount"));
        }
    }


    @Override
    public void addCreditBuyer(CreditBuyer dto) {
        Long shopId = StpKit.USER.getShopId(0L);
        dto.setShopId(shopId);
        commonVerify(dto);
        try {
            Assert.notEmpty(dto.getRepaymentMethod(), "{}({})不能为空", "还款方式", "repaymentMethod");
        } catch (IllegalArgumentException e) {
            throw new CzgException(e.getMessage());
        }
        if (!ArrayUtil.contains(new String[]{"total", "order"}, dto.getRepaymentMethod())) {
            throw new CzgException(StrUtil.format("{}({})不合法", "还款方式", "repaymentMethod"));
        }
        dto.setAccountBalance(dto.getCreditAmount());
        CreditBuyer entity = BeanUtil.copyProperties(dto, CreditBuyer.class);
        super.save(entity);
    }

    @Override
    public void updateCreditBuyer(CreditBuyer dto) {
        try {
            Assert.notEmpty(dto.getId(), "{}不能为空", "id");
        } catch (IllegalArgumentException e) {
            throw new CzgException(e.getMessage());
        }
        Long shopId = StpKit.USER.getShopId(0L);
        dto.setShopId(shopId);
        commonVerify(dto);
        CreditBuyer entity = getById(dto.getId());
        if (entity == null) {
            throw new CzgException("挂账人不存在");
        }
        //余额减去挂账金额   100 60  挂账40  修改后 如果是 80
        BigDecimal sub = NumberUtil.sub(dto.getCreditAmount(), entity.getCreditAmount());
        //修改后的余额
        BigDecimal balance = NumberUtil.add(entity.getAccountBalance(), sub);
        if (NumberUtil.isLess(balance, BigDecimal.ZERO)) {
            throw new CzgException("挂账额度不能小于已挂账金额");
        }
        BeanUtil.copyProperties(dto, entity, CopyOptions.create().setIgnoreNullValue(false).setIgnoreProperties("repaymentMethod", "accountBalance"));
        entity.setAccountBalance(balance);
        updateById(entity, false);
    }

    @Override
    public void deleteCreditBuyer(String id) {
        CreditBuyer entity = getById(id);
        if (entity == null) {
            throw new CzgException("挂账人不存在");
        }
        if (NumberUtil.isLess(entity.getAccountBalance(), entity.getCreditAmount())) {
            throw new CzgException("删除失败，有未还款挂账金额。");
        }
        Long shopId = StpKit.USER.getShopId(0L);
        UpdateChain.of(CreditBuyer.class)
                .set(CreditBuyer::getIsDel, SystemConstants.OneZero.ONE)
                .eq(CreditBuyer::getId, id)
                .eq(CreditBuyer::getShopId, shopId)
                .update();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CreditBuyerRepaymentVo repayment(CreditBuyerRepaymentParam param) {
        // 还款金额
        BigDecimal repaymentAmount = param.getRepaymentAmount();
        try {
            Assert.notEmpty(param.getId(), "{}不能为空", "id");
            Assert.notNull(repaymentAmount, "{}({})不能为空", "还款金额", "repaymentAmount");
            Assert.notNull(param.getPaymentMethod(), "{}({})不能为空", "支付方式", "paymentMethod");
        } catch (IllegalArgumentException e) {
            throw new CzgException(e.getMessage());
        }
        CreditBuyer dto = getById(param.getId());
        if (dto == null) {
            throw new CzgException("挂账人不存在");
        }
        Integer isDel = dto.getIsDel();
        if (isDel == SystemConstants.OneZero.ONE) {
            throw new CzgException("挂账人已删除");
        }
        if (!"total".equals(dto.getRepaymentMethod())) {
            throw new CzgException("此挂账人不能以【按总账户还款】进行还款");
        }
        if (NumberUtil.isLess(repaymentAmount, BigDecimal.ZERO)) {
            throw new CzgException("还款金额不能小于0");
        }

        CreditBuyer upEntity = new CreditBuyer();
        upEntity.setId(param.getId());
        upEntity.setAccountBalance(NumberUtil.add(dto.getAccountBalance(), repaymentAmount));
        super.updateById(upEntity);

        CreditPaymentRecord record2 = new CreditPaymentRecord();
        record2.setCreditBuyerId(param.getId());
        record2.setRepaymentAmount(repaymentAmount);
        record2.setPaymentMethod(param.getPaymentMethod());
        record2.setPaymentTime(LocalDateTime.now());
        record2.setRemark(param.getRemark());
        creditPaymentRecordMapper.insert(record2);
        if (NumberUtil.isGreaterOrEqual(dto.getAccountBalance(), dto.getCreditAmount())) {
            CreditBuyerRepaymentVo result = new CreditBuyerRepaymentVo();
            result.setRepaymentCount(0);
            result.setRepaymentAmount(repaymentAmount);
            result.setRepaymentMsg("账单无需还款，已转储至余额。");
            return result;
        }

        // 校验完毕，可以批量还款
        CreditBuyerOrderQueryParam where = new CreditBuyerOrderQueryParam();
        where.setCreditBuyerId(param.getId());
        where.setStatusList(List.of("unpaid", "partial"));
        List<CreditBuyerOrderDTO> list = creditBuyerOrderMapper.findCreditBuyerOrderList(where);
        if (CollUtil.isEmpty(list)) {
            throw new CzgException("没有需要还款的订单");
        }
        int repaymentCount = 0;
        List<CreditBuyerOrderDTO> orderList = list.stream().sorted(Comparator.comparing(CreditBuyerOrderDTO::getOrderId)).toList();
        for (CreditBuyerOrderDTO item : orderList) {
            // 未付款金额
            BigDecimal unpaidAmount = item.getUnpaidAmount();
            // 记录还款记录
            CreditPaymentRecord record = new CreditPaymentRecord();
            if (NumberUtil.isGreaterOrEqual(repaymentAmount, unpaidAmount)) {
                // 还全额
                UpdateChain.of(CreditBuyerOrder.class)
                        .set(CreditBuyerOrder::getStatus, "paid")
                        .set(CreditBuyerOrder::getPaidAmount, NumberUtil.add(item.getPaidAmount(), unpaidAmount))
                        .set(CreditBuyerOrder::getRemark, param.getRemark())
                        .set(CreditBuyerOrder::getLastPaymentMethod, param.getPaymentMethod())
                        .set(CreditBuyerOrder::getLastPaymentTime, LocalDateTime.now())
                        .eq(CreditBuyerOrder::getStatus, item.getStatus())
                        .eq(CreditBuyerOrder::getId, item.getId())
                        .eq(CreditBuyerOrder::getOrderId, item.getOrderId())
                        .eq(CreditBuyerOrder::getCreditBuyerId, item.getCreditBuyerId())
                        .eq(CreditBuyerOrder::getPaidAmount, item.getPaidAmount())
                        .update();
                record.setRepaymentAmount(unpaidAmount);
                repaymentAmount = NumberUtil.sub(repaymentAmount, unpaidAmount);
            } else if (NumberUtil.isLess(repaymentAmount, unpaidAmount)) {
                // 还部分
                UpdateChain.of(CreditBuyerOrder.class)
                        .set(CreditBuyerOrder::getStatus, "partial")
                        .set(CreditBuyerOrder::getPaidAmount, NumberUtil.add(item.getPaidAmount(), repaymentAmount))
                        .set(CreditBuyerOrder::getRemark, param.getRemark())
                        .set(CreditBuyerOrder::getLastPaymentMethod, param.getPaymentMethod())
                        .set(CreditBuyerOrder::getLastPaymentTime, LocalDateTime.now())
                        .eq(CreditBuyerOrder::getStatus, item.getStatus())
                        .eq(CreditBuyerOrder::getId, item.getId())
                        .eq(CreditBuyerOrder::getOrderId, item.getOrderId())
                        .eq(CreditBuyerOrder::getCreditBuyerId, item.getCreditBuyerId())
                        .eq(CreditBuyerOrder::getPaidAmount, item.getPaidAmount())
                        .update();
                record.setRepaymentAmount(repaymentAmount);
                repaymentAmount = BigDecimal.ZERO;
            }
            record.setCreditBuyerId(item.getCreditBuyerId());
            record.setOrderId(item.getOrderId());
            record.setPaymentMethod(param.getPaymentMethod());
            record.setPaymentTime(LocalDateTime.now());
            record.setRemark(param.getRemark());
            creditPaymentRecordMapper.insert(record);
            repaymentCount++;
            if (NumberUtil.equals(repaymentAmount, BigDecimal.ZERO)) {
                break;
            }
        }
        CreditBuyerRepaymentVo result = new CreditBuyerRepaymentVo();
        result.setRepaymentCount(repaymentCount);
        result.setRepaymentMsg(StrUtil.format("共计还款{}笔，还款金额：{}元，当前余额：{}元。",
                repaymentCount, NumberUtil.sub(param.getRepaymentAmount(), repaymentAmount), upEntity.getAccountBalance()));
        return result;
    }

}