package com.starry.admin.modules.shop.service.impl;

import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.yulichang.wrapper.MPJLambdaWrapper;
import com.starry.admin.common.exception.CustomException;
import com.starry.admin.modules.custom.module.entity.PlayCustomUserInfoEntity;
import com.starry.admin.modules.shop.mapper.PlayCouponInfoMapper;
import com.starry.admin.modules.shop.module.constant.CouponUseState;
import com.starry.admin.modules.shop.module.entity.PlayCouponInfoEntity;
import com.starry.admin.modules.shop.module.enums.CouponClaimConditionType;
import com.starry.admin.modules.shop.module.enums.CouponObtainChannel;
import com.starry.admin.modules.shop.module.enums.CouponOnlineState;
import com.starry.admin.modules.shop.module.enums.CouponValidityPeriodType;
import com.starry.admin.modules.shop.module.support.CouponInventoryPolicy;
import com.starry.admin.modules.shop.module.vo.PlayCouponInfoQueryVo;
import com.starry.admin.modules.shop.module.vo.PlayCouponInfoReturnVo;
import com.starry.admin.modules.shop.service.IPlayCouponDetailsService;
import com.starry.admin.modules.shop.service.IPlayCouponInfoService;
import com.starry.common.utils.IdUtils;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.Arrays;
import java.util.List;
import java.util.Optional;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

/**
 * 优惠券信息Service业务层处理
 *
 * @author admin
 * @since 2024-07-04
 */
@Service
public class PlayCouponInfoServiceImpl extends ServiceImpl<PlayCouponInfoMapper, PlayCouponInfoEntity>
        implements
            IPlayCouponInfoService {
    @Resource
    private PlayCouponInfoMapper playCouponInfoMapper;

    @Resource
    private IPlayCouponDetailsService playCouponDetailsService;

    /**
     * 获取优惠券不可用的原因
     *
     * @param couponInfo
     *            优惠券信息
     * @param placeType
     *            下单类型
     * @param commodityId
     *            商品ID
     * @param commodityQuantity
     *            商品数量
     * @return 不可用原因
     */
    @Override
    public String getCouponReasonForUnavailableUse(PlayCouponInfoEntity couponInfo, String placeType,
            String commodityId, Integer commodityQuantity, BigDecimal price) {
        if (StrUtil.isEmpty(commodityId) || commodityQuantity <= 0) {
            return "订单满1船票余额时可用";
        }
        boolean placeTypeSuccess = false;
        for (String string : couponInfo.getPlaceType()) {
            if (string.equals(placeType)) {
                placeTypeSuccess = true;
                break;
            }
        }
        if (!placeTypeSuccess) {
            return "订单类型不符合";
        }
        // 订单门槛不等0，并且订单金额小于订单门槛
        if (BigDecimal.ZERO.compareTo(couponInfo.getUseMinAmount()) != 0
                && price.multiply(new BigDecimal(commodityQuantity)).compareTo(couponInfo.getUseMinAmount()) <= -1) {
            return "订单门槛不符合";
        }
        return "";
    }

    @Override
    public Optional<String> getCouponDetailRestrictionReason(
            PlayCouponInfoEntity couponInfo,
            String useState,
            LocalDateTime obtainingTime) {
        if (couponInfo == null) {
            return Optional.of("优惠券不存在");
        }
        if (StrUtil.isBlank(useState)) {
            return Optional.of("优惠券状态异常");
        }

        CouponUseState state;
        try {
            state = CouponUseState.fromCode(useState);
        } catch (IllegalArgumentException ex) {
            return Optional.of("优惠券状态异常");
        }
        if (state != CouponUseState.UNUSED) {
            return Optional.of("优惠券已使用");
        }

        Optional<CouponOnlineState> onlineStateOpt = CouponOnlineState.fromCode(couponInfo.getCouponOnLineState());
        if (onlineStateOpt.isEmpty()) {
            return Optional.of("优惠券状态异常");
        }
        if (onlineStateOpt.get() != CouponOnlineState.ONLINE) {
            return Optional.of("优惠券已下架");
        }

        LocalDateTime now = LocalDateTime.now();
        CouponValidityPeriodType validityType = CouponValidityPeriodType
                .fromCode(couponInfo.getValidityPeriodType())
                .orElse(CouponValidityPeriodType.PERMANENT);
        if (validityType == CouponValidityPeriodType.FIXED_RANGE) {
            if (couponInfo.getProductiveTime() != null && now.isBefore(couponInfo.getProductiveTime())) {
                return Optional.of("优惠券未生效");
            }
            if (couponInfo.getExpirationTime() != null && now.isAfter(couponInfo.getExpirationTime())) {
                return Optional.of("优惠券已过期");
            }
        } else if (validityType == CouponValidityPeriodType.RELATIVE_DAYS) {
            Integer effectiveDay = couponInfo.getEffectiveDay();
            if (obtainingTime == null || effectiveDay == null || effectiveDay <= 0) {
                return Optional.of("优惠券有效期未配置");
            }
            LocalDateTime expiration = obtainingTime.plusDays(effectiveDay);
            if (now.isAfter(expiration)) {
                return Optional.of("优惠券已过期");
            }
        }
        return Optional.empty();
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void claimCouponForCustom(
            String couponId,
            PlayCustomUserInfoEntity customUserInfo,
            CouponObtainChannel obtainChannel) {
        if (customUserInfo == null) {
            throw new CustomException("顾客信息不存在");
        }
        CouponObtainChannel channel = obtainChannel != null ? obtainChannel : CouponObtainChannel.SELF_SERVICE;

        PlayCouponInfoEntity couponInfo = playCouponInfoMapper.selectByIdForUpdate(couponId);
        if (couponInfo == null) {
            throw new CustomException("优惠券不存在");
        }
        Optional<CouponOnlineState> onlineState = CouponOnlineState.fromCode(couponInfo.getCouponOnLineState());
        if (onlineState.isPresent() && onlineState.get() != CouponOnlineState.ONLINE) {
            throw new CustomException("优惠券已下架");
        }

        CouponInventoryPolicy inventoryPolicy = CouponInventoryPolicy
                .resolve(couponInfo.getCouponQuantity(), couponInfo.getRemainingQuantity());
        if (!inventoryPolicy.hasStock(couponInfo.getRemainingQuantity())) {
            throw new CustomException("优惠券已领完");
        }

        Integer maxQuantityPerUser = couponInfo.getClerkObtainedMaxQuantity();
        if (maxQuantityPerUser != null && maxQuantityPerUser > 0) {
            long claimed = playCouponDetailsService.countActiveByCustomAndCoupon(couponId, customUserInfo.getId());
            if (claimed >= maxQuantityPerUser) {
                throw new CustomException("优惠券已达到领取上限");
            }
        }

        int affected = playCouponInfoMapper.increaseIssuedAndConsumeRemaining(couponId);
        if (inventoryPolicy.consumesStock() && affected == 0) {
            throw new CustomException("优惠券已领完");
        }

        playCouponDetailsService.create(
                customUserInfo.getId(),
                customUserInfo.getNickname(),
                customUserInfo.getLevelId(),
                couponId,
                channel.getCode(),
                CouponUseState.UNUSED.getCode());
    }

    /**
     * 获取优惠券不可领取的原因
     *
     * @param entity
     *            优惠券实体
     * @param customUserInfo
     *            顾客实体
     * @return String
     * @author admin
     * @since 2024/7/8 14:44
     **/
    @Override
    public String getReasonForNotObtainingCoupons(PlayCouponInfoEntity entity,
            PlayCustomUserInfoEntity customUserInfo) {
        CouponInventoryPolicy inventoryPolicy = CouponInventoryPolicy
                .resolve(entity.getCouponQuantity(), entity.getRemainingQuantity());
        if (!inventoryPolicy.hasStock(entity.getRemainingQuantity())) {
            return "优惠券已领完";
        }
        if (customUserInfo != null && playCouponDetailsService != null) {
            Integer perUserLimit = entity.getClerkObtainedMaxQuantity();
            if (perUserLimit != null && perUserLimit > 0) {
                long claimed = playCouponDetailsService.countActiveByCustomAndCoupon(
                        entity.getId(),
                        customUserInfo.getId());
                if (claimed >= perUserLimit) {
                    return "优惠券已达到领取上限";
                }
            }
        }
        CouponClaimConditionType type = CouponClaimConditionType.of(entity.getClaimConditionType());
        switch (type) {
            case ALL:
                return "";
            case WHITELIST:
                if (entity.getCustomWhitelist() == null || entity.getCustomWhitelist().isEmpty()) {
                    return "未配置白名单";
                }
                return entity.getCustomWhitelist().contains(customUserInfo.getId()) ? "" : "非指定用户";
            case FILTER:
            default:
                // 顾客等级判断
                String msg = reasonForNotObtainingCoupons(entity.getCustomLevelCheckType(), entity.getCustomLevel(),
                        customUserInfo.getLevelId(), "0");
                if (StrUtil.isNotEmpty(msg)) {
                    return msg;
                }
                // 顾客性别判断
                msg = reasonForNotObtainingCoupons(entity.getCustomSexCheckType(), entity.getCustomSex(),
                        String.valueOf(customUserInfo.getSex()), "1");
                if (StrUtil.isNotEmpty(msg)) {
                    return msg;
                }
                // TODO: 关注状态、新用户等其他条件可在此扩展
                return "";
        }
    }

    /**
     * 获取优惠券不可领取的原因
     *
     * @param checkStatus
     *            是否配置了该项指标（0:未配置,1:已配置）
     * @param attributes
     *            配置的属性列表
     * @param attribute
     *            用户属性值
     * @param type
     *            条件类型(0:用户等级,1:用户性别)
     * @return String
     * @author admin
     * @since 2024/7/8 15:22
     **/
    public String reasonForNotObtainingCoupons(String checkStatus, List<String> attributes, String attribute,
            String type) {
        if ("0".equals(checkStatus)) {
            return "";
        }
        for (String s : attributes) {
            if (s.equals(attribute)) {
                return "";
            }
        }
        if ("0".equals(type)) {
            return "用户等级不匹配";
        }
        if ("1".equals(type)) {
            return "用户性别不匹配";
        }
        return "";
    }

    /**
     * 查询优惠券信息
     *
     * @param id
     *            优惠券信息主键
     * @return 优惠券信息
     */
    @Override
    public PlayCouponInfoEntity selectPlayCouponInfoById(String id) {
        PlayCouponInfoEntity entity = this.baseMapper.selectById(id);
        if (entity == null) {
            throw new CustomException("优惠券不存在");
        }
        return entity;
    }

    @Override
    public IPage<PlayCouponInfoReturnVo> selectByPage(PlayCouponInfoQueryVo vo) {
        MPJLambdaWrapper<PlayCouponInfoEntity> lambdaQueryWrapper = new MPJLambdaWrapper<>();
        lambdaQueryWrapper.selectAll(PlayCouponInfoEntity.class);
        lambdaQueryWrapper.orderByDesc(PlayCouponInfoEntity::getCreatedTime);
        return this.baseMapper.selectJoinPage(new Page<>(vo.getPageNum(), vo.getPageSize()),
                PlayCouponInfoReturnVo.class, lambdaQueryWrapper);
    }

    @Override
    public List<PlayCouponInfoEntity> queryAll() {
        MPJLambdaWrapper<PlayCouponInfoEntity> lambdaQueryWrapper = new MPJLambdaWrapper<>();
        lambdaQueryWrapper.selectAll(PlayCouponInfoEntity.class);
        lambdaQueryWrapper.orderByDesc(PlayCouponInfoEntity::getCreatedTime);
        return this.baseMapper.selectJoinList(PlayCouponInfoEntity.class, lambdaQueryWrapper);
    }

    /**
     * 查询优惠券信息列表
     *
     * @param playCouponInfo
     *            优惠券信息
     * @return 优惠券信息
     */
    @Override
    public IPage<PlayCouponInfoEntity> selectPlayCouponInfoByPage(PlayCouponInfoEntity playCouponInfo) {
        Page<PlayCouponInfoEntity> page = new Page<>(1, 10);
        return this.baseMapper.selectPage(page, new LambdaQueryWrapper<PlayCouponInfoEntity>());
    }

    /**
     * 新增优惠券信息
     *
     * @param playCouponInfo
     *            优惠券信息
     * @return 结果
     */
    @Override
    public boolean create(PlayCouponInfoEntity playCouponInfo) {
        if (StrUtil.isBlankIfStr(playCouponInfo.getId())) {
            playCouponInfo.setId(IdUtils.getUuid());
        }
        return save(playCouponInfo);
    }

    /**
     * 修改优惠券信息
     *
     * @param playCouponInfo
     *            优惠券信息
     * @return 结果
     */
    @Override
    public boolean update(PlayCouponInfoEntity playCouponInfo) {
        return updateById(playCouponInfo);
    }

    /**
     * 批量删除优惠券信息
     *
     * @param ids
     *            需要删除的优惠券信息主键
     * @return 结果
     */
    @Override
    public int deletePlayCouponInfoByIds(String[] ids) {
        return playCouponInfoMapper.deleteBatchIds(Arrays.asList(ids));
    }

    /**
     * 删除优惠券信息信息
     *
     * @param id
     *            优惠券信息主键
     * @return 结果
     */
    @Override
    public int deletePlayCouponInfoById(String id) {
        return playCouponInfoMapper.deleteById(id);
    }
}
