package com.cf.imes.module.system.service.funds.organamount;


import cn.hutool.core.date.LocalDateTimeUtil;
import cn.hutool.core.util.ObjectUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.cf.imes.framework.common.exception.ServiceException;
import com.cf.imes.framework.common.util.Assert.AssertUtils;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.mybatis.core.query.LambdaUpdateWrapperX;
import com.cf.imes.module.executor.api.funds.ExecutorFundsApi;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.AllOrganAmountRespVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganAmountRespVO;
import com.cf.imes.module.system.controller.admin.funds.organamount.vo.OrganRechargeAmountRespVO;
import com.cf.imes.module.system.service.funds.purchase.PurchaseService;
import com.cf.imes.module.system.controller.admin.funds.purchase.vo.OrgEarliestPurchaseProductRespVO;
import com.cf.imes.module.system.dal.dataobject.funds.organamount.OrganAmountDO;
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO;
import com.cf.imes.module.system.dal.dataobject.funds.purchase.PurchaseRecordDO;
import com.cf.imes.module.system.dal.mysql.funds.organamount.OrganAmountMapper;
import com.cf.imes.module.system.service.organ.OrganService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;

import jakarta.annotation.Resource;

import java.math.BigDecimal;

import static cn.hutool.core.date.DatePattern.NORM_DATETIME_FORMATTER;
import static com.cf.imes.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ORGAN_AMOUNT_NO_EXIST;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ORGAN_PRODUCT_PAY_AMOUNT_CHANGE_ERROR;
import static com.cf.imes.module.system.enums.ErrorCodeConstants.ORGAN_RECHARGE_AMOUNT_UPDATE_ERROR;

/**
 * @author 资金管理接口 实现类
 */
@Slf4j
@Service
public class OrganAmountServiceImpl implements OrganAmountService {


    @Resource
    private OrganAmountMapper organAmountMapper;

    @Resource
    private OrganService organService;

    @Resource
    private ExecutorFundsApi executorFundsApi;

    @Resource
    private PurchaseService purchaseService;

    @Override
    public OrganAmountDO validOrganAmount(Long organId) {
        OrganAmountDO organAmountDO = organAmountMapper.selectOne(new LambdaQueryWrapper<OrganAmountDO>().eq(OrganAmountDO::getOrganId, organId));
        AssertUtils.notEmpty(organAmountDO, ORGAN_AMOUNT_NO_EXIST);
        return organAmountDO;
    }

    @Override
    public OrganRechargeAmountRespVO recharge(Long organId, BigDecimal price, BigDecimal gift) {
        OrganAmountDO organAmountDO = organAmountMapper.selectOne(new LambdaQueryWrapper<OrganAmountDO>().eq(OrganAmountDO::getOrganId, organId));
        BigDecimal newAmount = organAmountDO.getAmount().add(price);
        BigDecimal newGift = null;
        if (ObjectUtil.isNotNull(gift)) {
            newGift = organAmountDO.getGiftAmount().add(gift);
        }

        int updated = organAmountMapper.update(new LambdaUpdateWrapperX<OrganAmountDO>()
                .eq(OrganAmountDO::getOrganId, organId)
                .eq(OrganAmountDO::getVersion, organAmountDO.getVersion())
                .setIfPresent(OrganAmountDO::getGiftAmount, newGift)
                .set(OrganAmountDO::getAmount, newAmount)
                .set(OrganAmountDO::getVersion, organAmountDO.getVersion() + 1));
        // 1. 首次更新失败，认为出现并发，再查一次再更新
        if (updated == 0) {
            organAmountDO = organAmountMapper.selectOne(new LambdaQueryWrapper<OrganAmountDO>().eq(OrganAmountDO::getOrganId, organId));
            newAmount = organAmountDO.getAmount().add(price);
            newGift = organAmountDO.getGiftAmount().add(gift);

            updated = organAmountMapper.update(new LambdaUpdateWrapperX<OrganAmountDO>()
                    .eq(OrganAmountDO::getOrganId, organId)
                    .eq(OrganAmountDO::getVersion, organAmountDO.getVersion())
                    .setIfPresent(OrganAmountDO::getGiftAmount, newGift)
                    .set(OrganAmountDO::getAmount, newAmount)
                    .set(OrganAmountDO::getVersion, organAmountDO.getVersion() + 1));
            // 2. 第二次更新失败，资金表可能不存在
            if (updated == 0) {
                throw exception(ORGAN_RECHARGE_AMOUNT_UPDATE_ERROR);
            } else {
                return new OrganRechargeAmountRespVO(ObjectUtil.isNull(newGift) ? newAmount : newAmount.add(newGift), newAmount, newGift);
            }
        } else {
            return new OrganRechargeAmountRespVO(ObjectUtil.isNull(newGift) ? newAmount : newAmount.add(newGift), newAmount, newGift);
        }
    }

    @Override
    public void productPay(OrganAmountDO organAmountDO) {
        int updated = organAmountMapper.update(new LambdaUpdateWrapper<OrganAmountDO>()
                .eq(OrganAmountDO::getOrganId, organAmountDO.getOrganId())
                .eq(OrganAmountDO::getVersion, organAmountDO.getVersion())
                .set(OrganAmountDO::getAmount, organAmountDO.getAmount())
                .set(OrganAmountDO::getGiftAmount, organAmountDO.getGiftAmount())
                .set(OrganAmountDO::getVersion, organAmountDO.getVersion() + 1));
        if (updated == 0) {
            throw new ServiceException(ORGAN_PRODUCT_PAY_AMOUNT_CHANGE_ERROR);
        }
    }

    @Override
    public OrganRechargeAmountRespVO refundProductOrganAmountBalanceAndGift(Long organId, BigDecimal balance, BigDecimal gift) {
        OrganAmountDO organAmountDO = organAmountMapper.selectOne(new LambdaQueryWrapper<OrganAmountDO>().eq(OrganAmountDO::getOrganId, organId));
        BigDecimal newAmount = organAmountDO.getAmount().add(balance);
        BigDecimal newGift = organAmountDO.getGiftAmount().add(gift);

        int updated = organAmountMapper.update(new LambdaUpdateWrapper<OrganAmountDO>()
                .eq(OrganAmountDO::getOrganId, organId)
                .eq(OrganAmountDO::getVersion, organAmountDO.getVersion())
                .set(OrganAmountDO::getAmount, newAmount)
                .set(OrganAmountDO::getGiftAmount, newGift)
                .set(OrganAmountDO::getVersion, organAmountDO.getVersion() + 1));
        // 1. 首次更新失败，认为出现并发，再查一次再更新
        if (updated == 0) {
            organAmountDO = organAmountMapper.selectOne(new LambdaQueryWrapper<OrganAmountDO>().eq(OrganAmountDO::getOrganId, organId));
            newAmount = organAmountDO.getAmount().add(balance);
            newGift = organAmountDO.getGiftAmount().add(gift);

            updated = organAmountMapper.update(new LambdaUpdateWrapper<OrganAmountDO>()
                    .eq(OrganAmountDO::getOrganId, organId)
                    .eq(OrganAmountDO::getVersion, organAmountDO.getVersion())
                    .set(OrganAmountDO::getAmount, newAmount)
                    .set(OrganAmountDO::getGiftAmount, newGift)
                    .set(OrganAmountDO::getVersion, organAmountDO.getVersion() + 1));
            // 2. 第二次更新失败，资金表可能不存在
            if (updated == 0) {
                throw exception(ORGAN_RECHARGE_AMOUNT_UPDATE_ERROR);
            } else {
                return new OrganRechargeAmountRespVO(newAmount.add(newGift), newAmount, newGift);
            }
        } else {
            return new OrganRechargeAmountRespVO(newAmount.add(newGift), newAmount, newGift);
        }
    }

    @Override
    public OrganAmountRespVO getOrganAmount(Long organId) {

        organService.validOrgan(organId);

        OrganAmountDO organAmountDO = validOrganAmount(organId);

        OrganAmountRespVO organAmountRespVO = BeanUtils.toBean(organAmountDO, OrganAmountRespVO.class);

        // 查询组织最早还有效的产品购买记录
        OrgEarliestPurchaseProductRespVO orgEarliestProductDetail = purchaseService.getOrgEarliestProductDetail(organId);
        if (ObjectUtil.isNotNull(orgEarliestProductDetail)) {
            // 购买记录
            PurchaseRecordDO purchaseRecordDO = orgEarliestProductDetail.getPurchaseRecordDO();
            // 购买记录关联的定价规则
            ProductsDetailDO productsDetailDO = orgEarliestProductDetail.getProductsDetailDO();

            organAmountRespVO.setProductEfficientDate(LocalDateTimeUtil.format(purchaseRecordDO.getEndTime(), NORM_DATETIME_FORMATTER));
            organAmountRespVO.setDuration(productsDetailDO.getDuration());
            organAmountRespVO.setDurationUnit(productsDetailDO.getDurationUnit());
            organAmountRespVO.setGiftDuration(productsDetailDO.getGiftDuration());
            organAmountRespVO.setGiftDurationUnit(productsDetailDO.getGiftDurationUnit());
        }

        // 查询可开票金额
        organAmountRespVO.setInvoiceableAmount(purchaseService.getInvoicingAmount(organId));
        return organAmountRespVO;

    }


    @Override
    public AllOrganAmountRespVO getOrganAmountAll() {

        AllOrganAmountRespVO respVO = new AllOrganAmountRespVO();

        BigDecimal allOrganAmount = organAmountMapper.selectAllOrganAmount();

        BigDecimal examineAmount = executorFundsApi.getToExamineAmount().getCheckedData();

        respVO.setAllOrganAmount(allOrganAmount);
        respVO.setToExamineAmount(examineAmount);

        return respVO;

    }


}
