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

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.pojo.PageResult;
import com.cf.imes.framework.common.util.Assert.AssertUtils;
import com.cf.imes.framework.common.util.i18n.core.util.I18nUtils;
import com.cf.imes.framework.common.util.object.BeanUtils;
import com.cf.imes.framework.mybatis.core.query.LambdaQueryWrapperX;
import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsPageReqVO;
import com.cf.imes.module.system.controller.admin.funds.products.vo.productDetails.ProductDetailsSaveReqVO;
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDO;
import com.cf.imes.module.system.dal.dataobject.funds.products.ProductsDetailDO;
import com.cf.imes.module.system.dal.mysql.funds.products.ProductsDetailMapper;
import com.cf.imes.module.system.dal.mysql.funds.products.ProductsMapper;
import com.cf.imes.module.system.enums.pay.ProductDurationUnitEnum;
import com.cf.imes.module.system.enums.products.ProductStatusEnum;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import jakarta.annotation.Resource;

import java.math.BigDecimal;

import static com.cf.imes.module.system.enums.ErrorCodeConstants.*;

/**
 * 产品明细 productsDetails Service 实现类
 *
 * @author 晨丰科技
 */
@Service
@Validated
public class ProductsDetailServiceImpl implements ProductsDetailService {

    @Resource
    private ProductsDetailMapper productDetailsMapper;

    @Resource
    private ProductsMapper productsMapper;

    @Resource
    private I18nUtils i18nUtils;

    @Override
    public Long create(ProductDetailsSaveReqVO createReqVO) {

        // 校验是否有这个产品
        validateProductExistAndNotOnList(createReqVO.getProductId());

        // 查询是否有重复的定价
        checkProductDetails(createReqVO);

        ProductsDetailDO productDetailsDO = BeanUtils.toBean(createReqVO, ProductsDetailDO.class);
        productDetailsMapper.insert(productDetailsDO);
        return productDetailsDO.getId();
    }


    @Override
    public void update(ProductDetailsSaveReqVO updateReqVO) {

        validateProductExistAndNotOnList(updateReqVO.getProductId());

        validateProductDetailsExists(updateReqVO.getId());

        // 校验同时长是否还有其他的定价规则
        checkProductDetails(updateReqVO);

        productDetailsMapper.update(new LambdaUpdateWrapper<ProductsDetailDO>()
                .eq(ProductsDetailDO::getId, updateReqVO.getId())
                .set(ProductsDetailDO::getDiscount, updateReqVO.getDiscount())
                .set(ProductsDetailDO::getDuration, updateReqVO.getDuration())
                .set(ProductsDetailDO::getDurationUnit, updateReqVO.getDurationUnit())
        );
    }

    @Override
    public void delete(Long id) {

        ProductsDetailDO productsDetailDO = validateProductDetailsExists(id);

        validateProductExistAndNotOnList(productsDetailDO.getProductId());

        productDetailsMapper.deleteById(id);

    }

    @Override
    public ProductsDetailDO get(Long id) {
        return validateProductDetailsExists(id);
    }

    @Override
    public PageResult<ProductsDetailDO> getPage(ProductDetailsPageReqVO pageReqVO) {
        return productDetailsMapper.selectPage(pageReqVO);
    }


    @Override
    public ProductsDetailDO validateProductDetailsExists(Long id) {
        if (id == null) {
            throw new ServiceException(PRODUCTS_DETAIL_NO_EXIST);
        }

        ProductsDetailDO productsDetailDO = productDetailsMapper.selectOne(new LambdaQueryWrapperX<ProductsDetailDO>()
                .eq(ProductsDetailDO::getId, id)
                .eq(ProductsDetailDO::getDeleted, false));

        if (productsDetailDO == null) {
            throw new ServiceException(PRODUCTS_DETAIL_NO_EXIST);
        }

        return productsDetailDO;
    }


    /**
     * 产品是否存在
     *
     * @param productId
     */
    @Override
    public ProductsDO validateProductExist(Long productId) {
        ProductsDO productsDO = productsMapper.selectOne(new LambdaQueryWrapperX<ProductsDO>()
                .eq(ProductsDO::getId, productId)
                .eq(ProductsDO::getDeleted, false));

        AssertUtils.notEmpty(productsDO, PRODUCTS_NO_EXIST);

        if (!productsDO.getStatus().equals(ProductStatusEnum.PRODUCT_UPDATES.getStatus())) {
            throw new ServiceException(PRODUCTS_NOT_NOLIST);
        }

        return productsDO;
    }

    /**
     * 校验产品存在并且未上架
     *
     * @param productId
     * @return
     */
    private ProductsDO validateProductExistAndNotOnList(Long productId) {
        ProductsDO productsDO = productsMapper.selectOne(new LambdaQueryWrapperX<ProductsDO>()
                .eq(ProductsDO::getId, productId)
                .eq(ProductsDO::getDeleted, false));

        AssertUtils.notEmpty(productsDO, PRODUCTS_NO_EXIST);

        if (productsDO.getStatus().equals(ProductStatusEnum.PRODUCT_UPDATES.getStatus())) {
            throw new ServiceException(PRODUCTS_DETAIL_NO_UPDATE);
        }

        return productsDO;
    }


    /**
     * 检查产品下是否有相同时长的规则
     *
     * @param createReqVO
     */
    private void checkProductDetails(ProductDetailsSaveReqVO createReqVO) {
        int count;
        Integer duration = createReqVO.getDuration();
        Integer durationUnit = createReqVO.getDurationUnit();
        // 时长去重
        count = productDetailsMapper.selectCountByDuration(createReqVO.getProductId(), createReqVO.getId(), duration, durationUnit);
        if (count > 0) {
            throw new ServiceException(PRODUCTS_DETAIL_DURATION_EXIST, duration, i18nUtils.getMessage(ProductDurationUnitEnum.getDesc(durationUnit)));
        }
    }

    @Override
    public BigDecimal getProductDetailOneYearDiscount(Long productId) {
        ProductsDetailDO productsDetailDO = productDetailsMapper.selectOne(new LambdaQueryWrapper<ProductsDetailDO>()
                .eq(ProductsDetailDO::getProductId, productId)
                .eq(ProductsDetailDO::getDuration, 1)
                .eq(ProductsDetailDO::getDurationUnit, ProductDurationUnitEnum.YEAR.getCode()));
        if (ObjectUtil.isNotNull(productsDetailDO)) {
            return productsDetailDO.getDiscount();
        } else {
            return BigDecimal.valueOf(100);
        }
    }
}
