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

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.convert.Convert;
import cn.hutool.core.lang.Assert;
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.entity.OrderInfo;
import com.czg.order.param.CreditBuyerOrderQueryParam;
import com.czg.order.service.CreditBuyerOrderService;
import com.czg.order.service.CreditBuyerService;
import com.czg.order.vo.CreditBuyerOrderSummaryVo;
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.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import com.github.pagehelper.PageParam;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.update.UpdateChain;
import com.mybatisflex.spring.service.impl.ServiceImpl;
import jakarta.annotation.Resource;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.List;

/**
 * 挂账账单
 *
 * @author Tankaikai tankaikai@aliyun.com
 * @since 1.0 2025-03-04
 */
@Service
public class CreditBuyerOrderServiceImpl extends ServiceImpl<CreditBuyerOrderMapper, CreditBuyerOrder> implements CreditBuyerOrderService {

    @Resource
    private CreditBuyerMapper creditBuyerMapper;
    @Resource
    private CreditPaymentRecordMapper creditPaymentRecordMapper;
    @Resource
    @Lazy
    private CreditBuyerService creditBuyerService;

    @Override
    public Page<CreditBuyerOrderDTO> getCreditBuyerOrderPage(CreditBuyerOrderQueryParam param) {
        PageParam pageParam = PageUtil.buildPageHelp();
        PageHelper.startPage(pageParam.getPageNum(), pageParam.getPageSize(), StrUtil.blankToDefault(pageParam.getOrderBy(), "order_id desc"));
        PageInfo<CreditBuyerOrderDTO> pageInfo = new PageInfo<>(super.mapper.findCreditBuyerOrderList(param));
        return PageUtil.convert(pageInfo);
    }

    @Override
    public CreditBuyerOrderSummaryVo summary(CreditBuyerOrderQueryParam param) {
        CreditBuyerOrderSummaryVo data = new CreditBuyerOrderSummaryVo();
        long count = super.mapper.getCreditBuyerOrderCount(param);
        // 总交易笔数
        data.setCount(count);
        // 总交易金额
        BigDecimal payAmount = super.mapper.getSumPayAmount(param);
        data.setPayAmountTotal(payAmount);

        // 待支付笔数
        param.setStatusList(List.of("unpaid", "partial"));
        long unpaidCount = super.mapper.getCreditBuyerOrderCount(param);
        data.setUnpaidCount(unpaidCount);
        param.setStatusList(List.of("paid", "partial"));
        BigDecimal paidAmount = super.mapper.getSumPaidAmount(param);
        param.setStatusList(List.of("unpaid", "partial"));
        BigDecimal unpaidAmount = super.mapper.getSumUnpaidAmount(param);
        data.setPaidAmountTotal(paidAmount);
        data.setUnpaidAmountTotal(unpaidAmount);
        return data;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void pay(CreditPaymentRecord record) {
        try {
            Assert.notNull(record.getCreditBuyerId(), "{}({})不能为空", "挂账人id", "creditBuyerId");
            Assert.notNull(record.getOrderId(), "{}({})不能为空", "订单id", "orderId");
            Assert.notNull(record.getRepaymentAmount(), "{}({})不能为空", "还款金额", "repaymentAmount");
            Assert.notEmpty(record.getPaymentMethod(), "{}({})不能为空", "支付方式", "paymentMethod");
            //Assert.notNull(record.getPaymentTime(), "{}({})不能为空", "还款时间", "paymentTime");
        } catch (IllegalArgumentException e) {
            throw new CzgException(e.getMessage());
        }
        CreditBuyer creditBuyer = creditBuyerMapper.selectOneById(record.getCreditBuyerId());
        if (creditBuyer == null) {
            throw new CzgException("挂账人不存在");
        }
        creditBuyer.setAccountBalance(NumberUtil.add(creditBuyer.getAccountBalance(), record.getRepaymentAmount()));
        CreditBuyer upCreditBuyer = new CreditBuyer();
        upCreditBuyer.setId(record.getCreditBuyerId());
        upCreditBuyer.setAccountBalance(creditBuyer.getAccountBalance());
        creditBuyerMapper.update(upCreditBuyer);
        String repaymentMethod = creditBuyer.getRepaymentMethod();
        if (!"order".equals(repaymentMethod)) {
            throw new CzgException("该挂账人不支持按订单付款");
        }
        CreditBuyerOrderQueryParam param = new CreditBuyerOrderQueryParam();
        param.setCreditBuyerId(record.getCreditBuyerId());
        param.setOrderId(Convert.toStr(record.getOrderId()));
        CreditBuyerOrder dto = getOne(query().eq(CreditBuyerOrder::getCreditBuyerId, record.getCreditBuyerId())
                .eq(CreditBuyerOrder::getOrderId, record.getOrderId()));
        if (dto == null) {
            throw new CzgException("挂账订单不存在");
        }
        if ("paid".equals(dto.getStatus())) {
            throw new CzgException("挂账订单已还清，无需还款");
        }
        if (NumberUtil.isLess(record.getRepaymentAmount(), BigDecimal.ZERO)) {
            throw new CzgException("还款金额不能小于0");
        }
        BigDecimal unpaidAmount = NumberUtil.sub(dto.getOrderAmount(), dto.getRefundAmount(), dto.getPaidAmount());
        if (NumberUtil.isGreater(record.getRepaymentAmount(), unpaidAmount)) {
            throw new CzgException("还款金额不能大于未支付金额");
        }
        CreditBuyerOrder entity = BeanUtil.copyProperties(dto, CreditBuyerOrder.class);
        if (NumberUtil.equals(record.getRepaymentAmount(), unpaidAmount)) {
            entity.setStatus("paid");
        } else {
            entity.setStatus("partial");
        }
        entity.setPaidAmount(NumberUtil.add(entity.getPaidAmount(), record.getRepaymentAmount()));
        entity.setLastPaymentTime(LocalDateTime.now());
        entity.setLastPaymentMethod(record.getPaymentMethod());
        entity.setRemark(record.getRemark());
        super.updateById(entity);
        record.setPaymentTime(LocalDateTime.now());
        creditPaymentRecordMapper.insert(record);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean save(OrderInfo orderInfo, String creditBuyerId, Long orderId) {
        if (StrUtil.isBlank(creditBuyerId)) {
            throw new CzgException("挂账人id不能为空");
        }
        CreditBuyer creditBuyer = creditBuyerService.getById(creditBuyerId);
        if (creditBuyer == null) {
            throw new CzgException("挂账人不存在");
        }
        Integer delFlag = creditBuyer.getIsDel();
        if (delFlag != null && delFlag == SystemConstants.OneZero.ONE) {
            throw new CzgException("挂账人已删除");
        }
        Integer status = creditBuyer.getStatus();
        if (status != null && status == SystemConstants.OneZero.ZERO) {
            throw new CzgException("挂账人已被停用");
        }
        if (orderInfo == null) {
            throw new CzgException("订单不存在");
        }
        // 账户余额
        BigDecimal accountBalance = creditBuyer.getAccountBalance();
        boolean greater = NumberUtil.isGreater(orderInfo.getOrderAmount(), accountBalance);
        if (greater) {
            throw new CzgException(StrUtil.format("剩余可挂账金额{} ，不足{}元", accountBalance, orderInfo.getOrderAmount()));
        }
        // 减余额
        creditBuyer.setAccountBalance(NumberUtil.sub(accountBalance, orderInfo.getOrderAmount()));
        CreditBuyer upCreditBuyer = new CreditBuyer();
        upCreditBuyer.setId(creditBuyerId);
        upCreditBuyer.setAccountBalance(creditBuyer.getAccountBalance());
        creditBuyerMapper.update(upCreditBuyer);

        CreditBuyerOrder entity = new CreditBuyerOrder();
        entity.setCreditBuyerId(creditBuyerId);
        entity.setOrderId(orderId);
        entity.setOrderAmount(orderInfo.getOrderAmount());
        //减去订单金额 余额仍大于挂账额度 则全额付款
        if (NumberUtil.isGreaterOrEqual(creditBuyer.getAccountBalance(), creditBuyer.getCreditAmount())) {
            entity.setPaidAmount(orderInfo.getOrderAmount());
            entity.setStatus("paid");
        } else {
            if (NumberUtil.isGreater(accountBalance, creditBuyer.getCreditAmount())) {
                entity.setStatus("partial");
                entity.setPaidAmount(NumberUtil.sub(accountBalance, creditBuyer.getCreditAmount()));
            } else {
                entity.setStatus("unpaid");
                entity.setPaidAmount(BigDecimal.ZERO);
            }
        }
        entity.setRefundAmount(BigDecimal.ZERO);
        entity.setLastPaymentTime(LocalDateTime.now());
        return save(entity);
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean partRefund(String creditBuyerId, Long orderId, String orderNo, BigDecimal refundAmount) {
        if (StrUtil.isBlank(creditBuyerId)) {
            throw new CzgException("挂账人id不能为空");
        }
        CreditBuyer creditBuyer = creditBuyerService.getById(creditBuyerId);
        if (creditBuyer == null) {
            throw new CzgException("挂账人不存在");
        }

        CreditBuyerOrderQueryParam param = new CreditBuyerOrderQueryParam();
        param.setCreditBuyerId(creditBuyerId);
        param.setOrderId(Convert.toStr(orderId));
        CreditBuyerOrder creditBuyerOrder = getOne(query().eq(CreditBuyerOrder::getCreditBuyerId, creditBuyerId).eq(CreditBuyerOrder::getOrderId, orderId));
        if (creditBuyerOrder == null) {
            throw new CzgException("挂账订单不存在");
        }
        // 已还款金额进行红冲
        CreditPaymentRecord record = new CreditPaymentRecord();
        record.setCreditBuyerId(creditBuyerId);
        record.setOrderId(orderId);
        record.setRepaymentAmount(NumberUtil.sub(BigDecimal.ZERO, refundAmount));
        record.setPaymentMethod("挂账退款");
        record.setPaymentTime(LocalDateTime.now());
        record.setRemark(StrUtil.format("挂账订单：{}，申请退款￥{}元，已恢复挂账额度。", orderNo, refundAmount));
        creditPaymentRecordMapper.insert(record);
        //退款金额减去  待支付金额
        BigDecimal sub = NumberUtil.sub(refundAmount, NumberUtil.sub(creditBuyerOrder.getOrderAmount(), creditBuyerOrder.getPaidAmount()));
        if (NumberUtil.isGreater(sub, BigDecimal.ZERO)) {
            CreditPaymentRecord flow = new CreditPaymentRecord();
            flow.setCreditBuyerId(creditBuyerId);
            flow.setOrderId(orderId);
            flow.setRepaymentAmount(sub);
            flow.setPaymentMethod("转储余额");
            flow.setPaymentTime(LocalDateTime.now());
            flow.setRemark(StrUtil.format("挂账订单：{}，申请退款￥{}元，由于此挂账订单已提前还款，溢出部分￥{}元将转储至账户余额。", orderNo, refundAmount, sub));
            creditPaymentRecordMapper.insert(flow);
            UpdateChain.of(CreditBuyerOrder.class)
                    .set(CreditBuyerOrder::getPaidAmount, NumberUtil.sub(creditBuyerOrder.getPaidAmount(), sub))
                    .set(CreditBuyerOrder::getRefundAmount, NumberUtil.add(creditBuyerOrder.getRefundAmount(), sub))
                    .eq(CreditBuyerOrder::getId, creditBuyerOrder.getId())
                    .update();
            // 退回余额
            creditBuyer.setAccountBalance(NumberUtil.add(creditBuyer.getAccountBalance(), sub));
            CreditBuyer entity = new CreditBuyer();
            entity.setId(creditBuyer.getId());
            entity.setAccountBalance(creditBuyer.getAccountBalance());
            creditBuyerService.updateById(entity);
        } else {
            UpdateChain.of(CreditBuyerOrder.class)
                    .set(CreditBuyerOrder::getRefundAmount, NumberUtil.add(creditBuyerOrder.getRefundAmount(), sub))
                    .eq(CreditBuyerOrder::getId, creditBuyerOrder.getId())
                    .update();
        }
        return true;
    }
}
