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.enums.DeleteEnum;
import com.czg.exception.CzgException;
import com.czg.order.dto.CreditBuyerDTO;
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.service.market.mapper.OrderInfoMapper;
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;
    @Resource
    private OrderInfoMapper orderInfoMapper;

    @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("挂账人不存在");
        }
        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()));
        CreditBuyerOrderDTO dto = super.mapper.getOne(param);
        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");
        }
        if (NumberUtil.isGreater(record.getRepaymentAmount(), dto.getUnpaidAmount())) {
            throw new CzgException("还款金额不能大于未支付金额");
        }
        CreditBuyerOrder entity = BeanUtil.copyProperties(dto, CreditBuyerOrder.class);
        if (NumberUtil.equals(record.getRepaymentAmount(), dto.getUnpaidAmount())) {
            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(String creditBuyerId, Long orderId) {
        if (StrUtil.isBlank(creditBuyerId)) {
            throw new CzgException("挂账人id不能为空");
        }
        CreditBuyerDTO creditBuyer = creditBuyerService.getCreditBuyerById(creditBuyerId);
        if (creditBuyer == null) {
            throw new CzgException("挂账人不存在");
        }
        Integer delFlag = creditBuyer.getIsDel();
        if (delFlag != null && delFlag == DeleteEnum.DELETED.value()) {
            throw new CzgException("挂账人已删除");
        }
        Integer status = creditBuyer.getStatus();
        if (status != null && status == DeleteEnum.NORMAL.value()) {
            throw new CzgException("挂账人已被停用");
        }
        OrderInfo orderInfo = orderInfoMapper.selectOneById(orderId);
        if (orderInfo == null) {
            throw new CzgException("订单不存在");
        }
        // 账户余额
        BigDecimal accountBalance = creditBuyer.getAccountBalance();
        // 如果有余额的话，从余额里面扣除，没有余额的话，从信用额度里面扣除，余额和信用额度都为0，则不允许挂账，余额+信用额度刚好够支付这笔订单的话需要同时减余额减信用额度
        if (NumberUtil.isGreaterOrEqual(accountBalance, orderInfo.getOrderAmount())) {
            // 减余额
            creditBuyer.setAccountBalance(NumberUtil.sub(accountBalance, orderInfo.getOrderAmount()));
            CreditBuyer dbRecord = BeanUtil.copyProperties(creditBuyer, CreditBuyer.class);
            creditBuyerMapper.update(dbRecord);
            // 记录还款记录
            CreditPaymentRecord record = new CreditPaymentRecord();
            record.setCreditBuyerId(creditBuyerId);
            record.setOrderId(orderId);
            record.setRepaymentAmount(orderInfo.getOrderAmount());
            record.setPaymentMethod("余额支付");
            record.setPaymentTime(LocalDateTime.now());
            record.setRemark("挂账时余额充足，直接从余额扣除");
            creditPaymentRecordMapper.insert(record);
            CreditBuyerOrder entity = new CreditBuyerOrder();
            entity.setCreditBuyerId(creditBuyerId);
            entity.setOrderId(orderId);
            entity.setPaidAmount(orderInfo.getOrderAmount());
            entity.setStatus("paid");
            entity.setLastPaymentTime(LocalDateTime.now());
            entity.setLastPaymentMethod(record.getPaymentMethod());
            entity.setRemark(record.getRemark());
            return super.save(entity);
        }
        CreditBuyerOrder entity = null;
        if (NumberUtil.isGreater(accountBalance, BigDecimal.ZERO)) {
            // 减余额
            creditBuyer.setAccountBalance(BigDecimal.ZERO);
            CreditBuyer dbRecord = BeanUtil.copyProperties(creditBuyer, CreditBuyer.class);
            creditBuyerMapper.update(dbRecord);
            // 记录还款记录
            CreditPaymentRecord record = new CreditPaymentRecord();
            record.setCreditBuyerId(creditBuyerId);
            record.setOrderId(orderId);
            record.setRepaymentAmount(accountBalance);
            record.setPaymentMethod("余额支付");
            record.setPaymentTime(LocalDateTime.now());
            record.setRemark("挂账时余额不足，先扣除现有余额，其他的从挂账额度中扣除");
            creditPaymentRecordMapper.insert(record);
            entity = new CreditBuyerOrder();
            entity.setCreditBuyerId(creditBuyerId);
            entity.setOrderId(orderId);
            entity.setPaidAmount(accountBalance);
            entity.setStatus("partial");
            entity.setLastPaymentTime(LocalDateTime.now());
            entity.setLastPaymentMethod(record.getPaymentMethod());
            entity.setRemark(record.getRemark());
            //super.save(entity);
            orderInfo.setPayAmount(NumberUtil.sub(orderInfo.getOrderAmount(), accountBalance));
        }
        // 剩余挂账额度
        BigDecimal remainingAmount = creditBuyer.getRemainingAmount();
        // 验证挂账金额是否大于剩余额度
        boolean greater = NumberUtil.isGreater(orderInfo.getOrderAmount(), remainingAmount);
        if (greater) {
            throw new CzgException(StrUtil.format("{}：￥{}不能大于剩余挂账额度({})", "挂账金额", orderInfo.getOrderAmount(), remainingAmount));
        }
        if (entity == null) {
            entity = new CreditBuyerOrder();
            entity.setStatus("unpaid");
            entity.setPaidAmount(BigDecimal.ZERO);
            entity.setCreditBuyerId(creditBuyerId);
            entity.setOrderId(orderId);
        }
        return super.saveOrUpdate(entity);
    }

    @Override
    @Deprecated
    @Transactional(rollbackFor = Exception.class)
    public boolean refund(String creditBuyerId, Long orderId) {
        if (StrUtil.isBlank(creditBuyerId)) {
            throw new CzgException("挂账人id不能为空");
        }
        CreditBuyer creditBuyer = creditBuyerService.getById(creditBuyerId);
        if (creditBuyer == null) {
            throw new CzgException("挂账人不存在");
        }
        OrderInfo orderInfo = orderInfoMapper.selectOneById(orderId);
        if (orderInfo == null) {
            throw new CzgException("订单不存在");
        }

        CreditBuyerOrderQueryParam param = new CreditBuyerOrderQueryParam();
        param.setCreditBuyerId(creditBuyerId);
        param.setOrderId(Convert.toStr(orderId));
        CreditBuyerOrderDTO dto = super.mapper.getOne(param);
        if (dto == null) {
            throw new CzgException("挂账订单不存在");
        }
        // 1.只挂账未还款的情况，直接删除挂账订单
        if ("unpaid".equals(dto.getStatus())) {
            super.mapper.deleteById(dto.getId());
            return true;
        }
        // 2.部分还款/已还款，删除挂账订单+红冲还款记录，并把已还款金额退回余额或挂账额度
        if ("partial".equals(dto.getStatus()) || "paid".equals(dto.getStatus())) {
            // 已还款金额
            BigDecimal paidAmount = dto.getPaidAmount();
            // 已还款金额进行红冲
            CreditPaymentRecord record = new CreditPaymentRecord();
            record.setCreditBuyerId(creditBuyerId);
            record.setOrderId(orderId);
            record.setRepaymentAmount(NumberUtil.sub(BigDecimal.ZERO, paidAmount));
            record.setPaymentMethod("挂账退款");
            record.setPaymentTime(LocalDateTime.now());
            record.setRemark(StrUtil.format("挂账订单：{}申请退款，已归还挂账额度或账户余额", orderInfo.getOrderNo()));
            creditPaymentRecordMapper.insert(record);
            // 删除挂账订单，恢复挂账额度
            super.mapper.deleteById(dto.getId());
            // 退回余额
            creditBuyer.setAccountBalance(NumberUtil.add(creditBuyer.getAccountBalance(), paidAmount));
            creditBuyerService.updateById(creditBuyer);
            return true;
        }
        return false;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean partRefund(String creditBuyerId, Long orderId, BigDecimal refundAmount) {
        if (StrUtil.isBlank(creditBuyerId)) {
            throw new CzgException("挂账人id不能为空");
        }
        CreditBuyerDTO creditBuyer = creditBuyerService.getCreditBuyerById(creditBuyerId);
        if (creditBuyer == null) {
            throw new CzgException("挂账人不存在");
        }
        OrderInfo orderInfo = orderInfoMapper.selectOneById(orderId);
        if (orderInfo == null) {
            throw new CzgException("订单不存在");
        }

        CreditBuyerOrderQueryParam param = new CreditBuyerOrderQueryParam();
        param.setCreditBuyerId(creditBuyerId);
        param.setOrderId(Convert.toStr(orderId));
        CreditBuyerOrderDTO dto = mapper.getOne(param);
        if (dto == 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("挂账订单：{}，申请退款￥{}元，已恢复挂账额度。", orderInfo.getOrderNo(), refundAmount));
        creditPaymentRecordMapper.insert(record);
        dto = mapper.getOne(param);
        BigDecimal sub = NumberUtil.sub(refundAmount, dto.getUnpaidAmount());
        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("挂账订单：{}，申请退款￥{}元，由于此挂账订单已提前还款，溢出部分￥{}元将转储至账户余额。", orderInfo.getOrderNo(), refundAmount, sub));
            creditPaymentRecordMapper.insert(flow);
            UpdateChain.of(CreditBuyerOrder.class)
                    .set(CreditBuyerOrder::getPaidAmount, NumberUtil.sub(dto.getPaidAmount(), sub))
                    .eq(CreditBuyerOrder::getId, dto.getId())
                    .update();
            // 退回余额
            creditBuyer.setAccountBalance(NumberUtil.add(creditBuyer.getAccountBalance(), sub));
            CreditBuyer entity = BeanUtil.copyProperties(dto, CreditBuyer.class);
            creditBuyerService.updateById(entity);
        }
        return true;
    }
}
