package com.yc.ship.module.marketing.api.coupon;

import com.yc.ship.framework.common.pojo.CommonResult;
import com.yc.ship.framework.common.util.object.BeanUtils;
import com.yc.ship.module.marketing.api.coupon.dto.CouponCheckReqDto;
import com.yc.ship.module.marketing.api.coupon.dto.CouponRespDto;
import com.yc.ship.module.marketing.api.coupon.dto.CouponUseReqDto;
import com.yc.ship.module.marketing.api.coupon.dto.CouponUsedRespDto;
import com.yc.ship.module.marketing.dal.dataobject.coupon.CouponDO;
import com.yc.ship.module.marketing.dal.dataobject.couponCode.CouponCodeDO;
import com.yc.ship.module.marketing.dal.dataobject.couponCodeUseRecord.CouponCodeUseRecordDO;
import com.yc.ship.module.marketing.dal.mysql.couponCode.CouponCodeMapper;
import com.yc.ship.module.marketing.dal.mysql.couponCodeUseRecord.CouponCodeUseRecordMapper;
import com.yc.ship.module.marketing.enums.common.EnableStateEnum;
import com.yc.ship.module.marketing.enums.common.YesOrNoEnum;
import com.yc.ship.module.marketing.enums.coupon.CouponAuditStateEnum;
import com.yc.ship.module.marketing.enums.coupon.CouponCodeUseStateEnum;
import com.yc.ship.module.marketing.enums.coupon.CouponEffectiveTypeEnum;
import com.yc.ship.module.marketing.enums.coupon.CouponTypeEnum;
import com.yc.ship.module.marketing.service.coupon.CouponService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.LocalDateTime;

import static com.yc.ship.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.yc.ship.module.marketing.enums.ErrorCodeConstants.*;


/**
 * 优惠券 API 实现类
 * @author lfy
 */
@RestController // 提供 RESTfull API 接口，给 Feign 调用
@Validated
public class CouponApiImpl  implements CouponApi{

    @Resource
    private CouponService couponService;

    @Resource
    private CouponCodeMapper couponCodeMapper;

    @Resource
    private CouponCodeUseRecordMapper couponCodeUseRecordMapper;
    @Override
    public CommonResult<CouponRespDto> checkCoupon(CouponCheckReqDto reqDto) {
        if(reqDto.getTravelDate() == null) {
            reqDto.setTravelDate(LocalDateTime.now());
        }
        CouponDO couponDO = couponService.getByCouponCodeId(reqDto.getCouponCodeId());
        CouponCodeDO couponCodeDO = couponCodeMapper.selectById(reqDto.getCouponCodeId());
        //1.检查优惠券状态
        if(couponDO == null) {
            throw exception(COUPON_NOT_EXISTS);
        }
        if(!couponDO.getAuditState().equals(CouponAuditStateEnum.AUDIT_PASS.getType())) {
            throw exception(COUPON_NOT_AUDIT_PASS);
        }
        if(couponDO.getState() != EnableStateEnum.ENABLE.getType()) {
            throw exception(COUPON_NOT_ENABLE);
        }
        //2.检查优惠券有效期
        Integer effectiveType = couponDO.getEffectiveType();
        if(effectiveType == CouponEffectiveTypeEnum.RELATIVE_TIME.getType()) {
            //相对时间
            couponDO.setEffectiveStart(couponCodeDO.getCreateTime());
            couponDO.setEffectiveEnd(couponCodeDO.getCreateTime().plusMinutes(couponDO.getEffectiveTime()));
        }
            //判断是否在有效期内
        if(couponDO.getEffectiveStart().isAfter(reqDto.getTravelDate()) || couponDO.getEffectiveEnd().isBefore(reqDto.getTravelDate())) {
            throw exception(COUPON_NOT_EFFECTIVE);
        }
        //3.判断优惠券码是否属于当前用户
        if(!(couponCodeDO.getMemberId().equals(reqDto.getMemberId()))) {
            throw exception(COUPON_CODE_NOT_BELONG_TO_USER);
        }
        //4.判断优惠金额是否和传入的一致
        BigDecimal couponAmount = getCouponAmount(couponDO, reqDto.getAmount());
        if(couponAmount.compareTo(reqDto.getAmount().subtract(reqDto.getPayAmount())) < 0) {
            throw exception(COUPON_AMOUNT_ERROR);
        }
        //5.判断优惠券码是否已使用
        if(couponCodeDO == null) {
            throw exception(COUPON_CODE_NOT_EXISTS);
        }
        if(couponCodeDO.getState() == CouponCodeUseStateEnum.USED.getType()) {
            throw exception(COUPON_CODE_ALREADY_USED);
        }
        return CommonResult.success(BeanUtils.toBean(couponDO, CouponRespDto.class));
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommonResult<Boolean> useCoupon(CouponUseReqDto reqDto) {
        CouponCodeDO couponCodeDO = couponCodeMapper.selectById(reqDto.getCouponCodeId());
        //1.修改优惠券码状态为已使用
        couponCodeDO.setState(CouponCodeUseStateEnum.USED.getType()).setUseTime(LocalDateTime.now());
        couponCodeMapper.updateById(couponCodeDO);
        //2.添加优惠券码使用记录
        CouponCodeUseRecordDO couponCodeUseRecordDO = new CouponCodeUseRecordDO();
        Long couponId = couponCodeDO.getCouponId();
        couponCodeUseRecordDO.setCouponCodeId(couponCodeDO.getId())
                .setCouponId(couponId)
                .setOrderId(reqDto.getOrderId())
                .setSpuId(reqDto.getProductId())
                .setAmount(reqDto.getAmount().subtract(reqDto.getPayAmount()));
        couponCodeUseRecordMapper.insert(couponCodeUseRecordDO);
        //3.判断是否使用后继续发券
        CouponDO coupon = couponService.getCoupon(couponId);
        Integer useAfter = coupon.getUseAfter();
        if(useAfter.equals(YesOrNoEnum.YES.getType())) {
            couponService.receiveCoupon(reqDto.getMemberId(), couponId);
        }
        return CommonResult.success(true);
    }

    /**
     * 获取优惠金额
     * @param couponDO
     * @param orderAmount
     * @return
     */
    private BigDecimal getCouponAmount(CouponDO couponDO, BigDecimal orderAmount) {
        BigDecimal amount = BigDecimal.ZERO;
        //优惠券类型
        Integer type = couponDO.getType();
        //最大减免
        BigDecimal maximum = couponDO.getMaximum();
        //满足金额
        BigDecimal basic = couponDO.getBasic();
        //优惠券额度
        BigDecimal quota = couponDO.getQuota();
        if(type == CouponTypeEnum.COUPON_TYPE_CASH.getType()){
            amount = quota;
        }else if(type == CouponTypeEnum.COUPON_TYPE_REDUCTION.getType()){
            if(basic == null || basic.compareTo(BigDecimal.ZERO) == 0) {
                amount = maximum;
            }else{
                //判断可以满减多少次
                BigDecimal count = orderAmount.divide(basic, 2, RoundingMode.DOWN);
                int i = count.intValue();
                BigDecimal multiply = quota.multiply(BigDecimal.valueOf(i));
                if(multiply.compareTo(maximum)>=0) {
                    amount = maximum;
                }else {
                    amount = multiply;
                }
            }
        }else if(type == CouponTypeEnum.COUPON_TYPE_DISCOUNT.getType()){
            BigDecimal oneHundred = new BigDecimal(100);
            BigDecimal discount = oneHundred.subtract(quota);
            discount = discount.divide(oneHundred, 2, RoundingMode.DOWN);
            BigDecimal multiply = orderAmount.multiply(discount);
            amount = multiply;
        }
        return amount;
    }


    @Override
    @Transactional(rollbackFor = Exception.class)
    public CommonResult<Boolean> refundCoupon(Long orderId) {
        CouponCodeUseRecordDO couponCodeUseRecordDO = couponCodeUseRecordMapper.selectOne(CouponCodeUseRecordDO::getOrderId, orderId);
        if (couponCodeUseRecordDO != null) {
            //删除使用记录
            couponCodeUseRecordMapper.deleteById(couponCodeUseRecordDO.getId());
            //修改券码为未使用
            CouponCodeDO couponCodeDO = couponCodeMapper.selectById(couponCodeUseRecordDO.getCouponCodeId());
            Long couponId = couponCodeDO.getCouponId();
            CouponDO coupon = couponService.getCoupon(couponId);
            if(coupon.getUseAfter().equals(YesOrNoEnum.NO.getType())) {
                //如果是不继续发券，则直接修改为未使用
                couponCodeMapper.updateById(couponCodeDO.setState(CouponCodeUseStateEnum.UNUSED.getType()));
            }else if(coupon.getUseAfter().equals(YesOrNoEnum.YES.getType())) {
                //是继续发券，则直接删除券码
                couponCodeMapper.deleteById(couponCodeDO.getId());
            }
        }
        return CommonResult.success(true);
    }

    @Override
    public CommonResult<CouponUsedRespDto> getUsedCoupon(Long orderId) {
        CouponUsedRespDto respDto = new CouponUsedRespDto();
        CouponCodeUseRecordDO couponCodeUseRecordDO = couponCodeUseRecordMapper.selectOne(CouponCodeUseRecordDO::getOrderId, orderId);
        if(couponCodeUseRecordDO != null) {
            respDto.setCouponCodeId(couponCodeUseRecordDO.getCouponCodeId());
            respDto.setAmount(couponCodeUseRecordDO.getAmount());
            CouponDO couponDO = couponService.getCoupon(couponCodeUseRecordDO.getCouponId());
            respDto.setBasic(couponDO.getBasic());
            respDto.setMaximum(couponDO.getMaximum());
            respDto.setQuota(couponDO.getQuota());
            respDto.setType(couponDO.getType());
            respDto.setName(couponDO.getName());
        }
        return CommonResult.success(respDto);
    }


}
