package shop.alien.dining.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import shop.alien.dining.feign.AlienStoreFeign;
import shop.alien.dining.service.DiningCouponService;
import shop.alien.dining.util.TokenUtil;
import shop.alien.entity.result.R;
import shop.alien.entity.store.LifeDiscountCoupon;
import shop.alien.entity.store.LifeDiscountCouponUser;
import shop.alien.entity.store.vo.LifeDiscountCouponVo;
import shop.alien.mapper.LifeDiscountCouponMapper;
import shop.alien.mapper.LifeDiscountCouponUserMapper;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.stream.Collectors;

/**
 * 点餐模块-优惠券服务实现（透传 Feign 调 store，满足小程序我的优惠券/详情/选券）
 *
 * @author ssk
 * @version 1.0
 * @date 2025/1/29
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class DiningCouponServiceImpl implements DiningCouponService {

    private final AlienStoreFeign alienStoreFeign;
    private final LifeDiscountCouponUserMapper lifeDiscountCouponUserMapper;
    private final LifeDiscountCouponMapper lifeDiscountCouponMapper;

    @Override
    public R<List<LifeDiscountCouponVo>> getUserCouponList(String authorization, int page, int size, String tabType, Integer type, Integer couponType, String storeId, String storeKeyword) {
        log.info("DiningCouponService.getUserCouponList page={}, size={}, tabType={}, type={}, couponType={}, storeId={}, storeKeyword={}", page, size, tabType, type, couponType, storeId, storeKeyword);
        try {
            // 参数校验
            if (StringUtils.isEmpty(tabType)) {
                log.warn("tabType参数为空");
                return R.fail("分页类型不能为空");
            }
            if (page < 1) {
                page = 1;
            }
            if (size < 1 || size > 100) {
                size = 10;
            }
            
            R<List<LifeDiscountCouponVo>> result = alienStoreFeign.getUserCouponList(authorization, tabType, page, size, type, couponType, storeId, storeKeyword);
            if (result == null) {
                log.error("Feign调用返回null");
                return R.fail("获取优惠券列表失败：服务返回为空");
            }
            // 如果 Feign 返回的是失败结果，直接返回
            if (!result.isSuccess()) {
                log.warn("Feign调用返回失败: code={}, msg={}", result.getCode(), result.getMsg());
                return result;
            }
            return result;
        } catch (Exception e) {
            log.error("DiningCouponService.getUserCouponList ERROR: {}", e.getMessage(), e);
            return R.fail("获取优惠券列表失败: " + e.getMessage());
        }
    }

    @Override
    public R<LifeDiscountCouponVo> getCounponDetailById(String authorization, String counponId) {
        log.info("DiningCouponService.getCounponDetailById counponId={}", counponId);
        try {
            R<LifeDiscountCouponVo> result = alienStoreFeign.getCounponDetailById(authorization, counponId);
            if (result == null) {
                return R.fail("获取优惠券详情失败");
            }
            return result;
        } catch (Exception e) {
            log.error("DiningCouponService.getCounponDetailById ERROR Msg={}", e.getMessage());
            return R.fail("获取优惠券详情失败");
        }
    }

    @Override
    public R<Map<String, Object>> getStoreUserUsableCouponList(String authorization, String storeId, BigDecimal amount, Integer couponType) {
        log.info("DiningCouponService.getStoreUserUsableCouponList storeId={}, amount={}, couponType={}", storeId, amount, couponType);
        try {
            R<Map<String, Object>> result = alienStoreFeign.getStoreUserUsableCouponList(authorization, storeId, amount, couponType);
            if (result == null) {
                return R.fail("获取门店可用优惠券列表失败");
            }
            return result;
        } catch (Exception e) {
            log.error("DiningCouponService.getStoreUserUsableCouponList ERROR Msg={}", e.getMessage());
            return R.fail("获取门店可用优惠券列表失败");
        }
    }

    @Override
    public R<List<LifeDiscountCouponVo>> getUserOwnedCoupons(String storeId, BigDecimal amount) {
        log.info("查询用户拥有的优惠券, storeId={}, amount={}", storeId, amount);

        try {
            // 获取当前用户ID
            Integer userId = TokenUtil.getCurrentUserId();
            if (userId == null) {
                return R.fail("用户未登录");
            }

            // 查询用户拥有的优惠券（未使用且未过期的）
            LambdaQueryWrapper<LifeDiscountCouponUser> userWrapper = new LambdaQueryWrapper<>();
            userWrapper.eq(LifeDiscountCouponUser::getUserId, userId);
            userWrapper.eq(LifeDiscountCouponUser::getStatus, 0); // 0：待使用
            userWrapper.eq(LifeDiscountCouponUser::getDeleteFlag, 0);
            userWrapper.and(w -> w.isNull(LifeDiscountCouponUser::getExpirationTime)
                    .or()
                    .ge(LifeDiscountCouponUser::getExpirationTime, LocalDate.now()));
            userWrapper.orderByDesc(LifeDiscountCouponUser::getReceiveTime);
            userWrapper.orderByDesc(LifeDiscountCouponUser::getId);
            List<LifeDiscountCouponUser> userCoupons = lifeDiscountCouponUserMapper.selectList(userWrapper);

            if (userCoupons == null || userCoupons.isEmpty()) {
                log.info("用户没有可用的优惠券, userId={}", userId);
                return R.data(new ArrayList<>());
            }

            List<Integer> couponIds = userCoupons.stream()
                    .map(LifeDiscountCouponUser::getCouponId)
                    .filter(Objects::nonNull)
                    .distinct()
                    .collect(Collectors.toList());
            if (couponIds.isEmpty()) {
                return R.data(new ArrayList<>());
            }

            // 模板含逻辑删除：用户已领的券在商家删除模板后仍要能展示属性（与 store 端 includeDeleted 一致）
            List<LifeDiscountCoupon> coupons = lifeDiscountCouponMapper.selectByIdsIncludeDeleted(couponIds);
            if (coupons == null) {
                coupons = Collections.emptyList();
            }
            if (StringUtils.hasText(storeId)) {
                String sid = storeId.trim();
                coupons = coupons.stream()
                        .filter(c -> c != null && sid.equals(c.getStoreId()))
                        .collect(Collectors.toList());
            }

            if (coupons.isEmpty()) {
                log.info("未找到优惠券详情, userId={}, couponIds={}", userId, couponIds);
                return R.data(new ArrayList<>());
            }

            Map<Integer, LifeDiscountCoupon> templateById = coupons.stream()
                    .collect(Collectors.toMap(LifeDiscountCoupon::getId, c -> c, (a, b) -> a));

            LocalDate now = LocalDate.now();
            List<LifeDiscountCouponVo> couponVos = new ArrayList<>();
            for (LifeDiscountCouponUser userCoupon : userCoupons) {
                Integer cid = userCoupon.getCouponId();
                if (cid == null) {
                    continue;
                }
                LifeDiscountCoupon coupon = templateById.get(cid);
                if (coupon == null) {
                    continue;
                }
                if (!passesOwnedCouponUsableFilters(coupon, userCoupon, now)) {
                    continue;
                }
                couponVos.add(convertToVo(coupon, userCoupon));
            }

            sortOwnedCouponsForCheckout(couponVos, amount); // amount 仅参与排序，不参与过滤

            log.info("查询用户拥有的优惠券成功, userId={}, count={}", userId, couponVos.size());
            return R.data(couponVos);

        } catch (Exception e) {
            log.error("查询用户拥有的优惠券失败: {}", e.getMessage(), e);
            return R.fail("查询用户拥有的优惠券失败: " + e.getMessage());
        }
    }

    @Override
    public R<List<LifeDiscountCouponVo>> getStoreUserCouponList(String authorization, String storeId, Integer couponType) {
        log.info("DiningCouponService.getStoreUserCouponList storeId={}, couponType={}", storeId, couponType);
        try {
            R<List<LifeDiscountCouponVo>> result = alienStoreFeign.getStoreUserCouponList(authorization, storeId, couponType);
            if (result == null) {
                return R.fail("获取该用户该店铺优惠券列表失败");
            }
            return result;
        } catch (Exception e) {
            log.error("DiningCouponService.getStoreUserCouponList ERROR Msg={}", e.getMessage());
            return R.fail("获取该用户该店铺优惠券列表失败");
        }
    }

    @Override
    public R<IPage<LifeDiscountCouponVo>> getStoreAllCouponList(String authorization, int page, int size, String storeId,
                                                                String couponName, String tab, int couponsFromType,
                                                                int couponStatus, Integer couponType) {
        log.info("DiningCouponService.getStoreAllCouponList storeId={}, page={}, size={}, couponName={}, tab={}, couponsFromType={}, couponStatus={}, couponType={}",
                storeId, page, size, couponName, tab, couponsFromType, couponStatus, couponType);
        try {
            // Feign 返回 Page 类型（具体实现类），但 Service 接口使用 IPage（接口类型）
            // Page 实现了 IPage，所以可以直接返回
            R<com.baomidou.mybatisplus.extension.plugins.pagination.Page<LifeDiscountCouponVo>> result = alienStoreFeign.getStoreAllCouponList(
                    authorization, page, size, storeId, couponName, tab, couponsFromType, couponStatus, couponType);
            if (result == null) {
                return R.fail("获取该店铺所有优惠券列表失败");
            }
            // Page 实现了 IPage 接口，可以直接转换
            return R.data(result.getData());
        } catch (Exception e) {
            log.error("DiningCouponService.getStoreAllCouponList ERROR Msg={}", e.getMessage(), e);
            return R.fail("获取该店铺所有优惠券列表失败");
        }
    }

    @Override
    public R<List<LifeDiscountCouponVo>> getUserOwnedCouponsByStore(String storeId, Integer couponType) {
        log.info("查询用户目前所拥有的优惠券, storeId={}, couponType={}", storeId, couponType);

        try {
            // 获取当前用户ID
            Integer userId = TokenUtil.getCurrentUserId();
            if (userId == null) {
                return R.fail("用户未登录");
            }

            // 查询用户拥有的优惠券（未使用且未过期的）
            LambdaQueryWrapper<LifeDiscountCouponUser> userWrapper = new LambdaQueryWrapper<>();
            userWrapper.eq(LifeDiscountCouponUser::getUserId, userId);
            userWrapper.eq(LifeDiscountCouponUser::getStatus, 0); // 0：待使用
            userWrapper.eq(LifeDiscountCouponUser::getDeleteFlag, 0);
            userWrapper.and(w -> w.isNull(LifeDiscountCouponUser::getExpirationTime)
                    .or()
                    .ge(LifeDiscountCouponUser::getExpirationTime, LocalDate.now()));
            List<LifeDiscountCouponUser> userCoupons = lifeDiscountCouponUserMapper.selectList(userWrapper);

            if (userCoupons == null || userCoupons.isEmpty()) {
                log.info("用户没有可用的优惠券, userId={}", userId);
                return R.data(new ArrayList<>());
            }

            // 获取优惠券ID列表
            List<Integer> couponIds = userCoupons.stream()
                    .map(LifeDiscountCouponUser::getCouponId)
                    .collect(Collectors.toList());

            // 查询优惠券详情
            LambdaQueryWrapper<LifeDiscountCoupon> couponWrapper = new LambdaQueryWrapper<>();
            couponWrapper.in(LifeDiscountCoupon::getId, couponIds);
            couponWrapper.eq(LifeDiscountCoupon::getDeleteFlag, 0);
            // 如果提供了商铺ID，则只查询该商铺的优惠券
            if (StringUtils.hasText(storeId)) {
                couponWrapper.eq(LifeDiscountCoupon::getStoreId, storeId);
            }
            // 如果提供了优惠券类型，则只查询该类型的优惠券
            if (couponType != null) {
                couponWrapper.eq(LifeDiscountCoupon::getCouponType, couponType);
            }
            List<LifeDiscountCoupon> coupons = lifeDiscountCouponMapper.selectList(couponWrapper);

            if (coupons == null || coupons.isEmpty()) {
                log.info("未找到优惠券详情, userId={}, storeId={}, couponIds={}", userId, storeId, couponIds);
                return R.data(new ArrayList<>());
            }

            // 转换为VO并设置用户券ID，同时过滤掉已过期和未在使用时间内的优惠券
            LocalDate now = LocalDate.now();
            List<LifeDiscountCouponVo> couponVos = new ArrayList<>();
            for (LifeDiscountCoupon coupon : coupons) {
                // 找到对应的用户券
                LifeDiscountCouponUser userCoupon = userCoupons.stream()
                        .filter(uc -> uc.getCouponId().equals(coupon.getId()))
                        .findFirst()
                        .orElse(null);

                if (userCoupon == null) {
                    continue;
                }

                // 过滤1：检查用户券的过期时间（expirationTime）
                if (userCoupon.getExpirationTime() != null && now.isAfter(userCoupon.getExpirationTime())) {
                    log.debug("过滤已过期的用户券, couponId={}, expirationTime={}, now={}", 
                            coupon.getId(), userCoupon.getExpirationTime(), now);
                    continue;
                }

                // 过滤2：检查优惠券的使用时间范围（startDate 和 endDate）
                // 如果优惠券有设置使用时间范围，则检查当前日期是否在范围内
                if (coupon.getStartDate() != null || coupon.getEndDate() != null) {
                    boolean inTimeRange = true;
                    if (coupon.getStartDate() != null && now.isBefore(coupon.getStartDate())) {
                        // 当前日期早于开始日期，未在使用时间内
                        inTimeRange = false;
                    }
                    if (coupon.getEndDate() != null && now.isAfter(coupon.getEndDate())) {
                        // 当前日期晚于结束日期，未在使用时间内
                        inTimeRange = false;
                    }
                    if (!inTimeRange) {
                        log.debug("过滤未在使用时间内的优惠券, couponId={}, startDate={}, endDate={}, now={}", 
                                coupon.getId(), coupon.getStartDate(), coupon.getEndDate(), now);
                        continue;
                    }
                }

                // 过滤3：检查优惠券的有效期（validDate）
                if (coupon.getValidDate() != null && now.isAfter(coupon.getValidDate())) {
                    log.debug("过滤已过期的优惠券（validDate）, couponId={}, validDate={}, now={}", 
                            coupon.getId(), coupon.getValidDate(), now);
                    continue;
                }

                LifeDiscountCouponVo vo = convertToVo(coupon, userCoupon);
                couponVos.add(vo);
            }

            // 按创建时间倒序排列（最新的在前）
            couponVos.sort((vo1, vo2) -> {
                if (vo1.getCreatedTime() == null && vo2.getCreatedTime() == null) {
                    return 0;
                }
                if (vo1.getCreatedTime() == null) {
                    return 1;
                }
                if (vo2.getCreatedTime() == null) {
                    return -1;
                }
                return vo2.getCreatedTime().compareTo(vo1.getCreatedTime()); // 降序排列
            });

            log.info("查询用户拥有的优惠券成功, userId={}, storeId={}, count={}", userId, storeId, couponVos.size());
            return R.data(couponVos);

        } catch (Exception e) {
            log.error("查询用户拥有的优惠券失败: {}", e.getMessage(), e);
            return R.fail("查询用户拥有的优惠券失败: " + e.getMessage());
        }
    }

    /**
     * /userOwned：排除已过期（用户券有效期、模板可使用日期、模板 validDate）。
     */
    private boolean passesOwnedCouponUsableFilters(LifeDiscountCoupon coupon, LifeDiscountCouponUser userCoupon, LocalDate now) {
        if (userCoupon.getExpirationTime() != null && now.isAfter(userCoupon.getExpirationTime())) {
            log.debug("过滤已过期的用户券, userCouponId={}, couponId={}, expirationTime={}, now={}",
                    userCoupon.getId(), coupon.getId(), userCoupon.getExpirationTime(), now);
            return false;
        }

        if (coupon.getStartDate() != null || coupon.getEndDate() != null) {
            if (coupon.getStartDate() != null && now.isBefore(coupon.getStartDate())) {
                return false;
            }
            if (coupon.getEndDate() != null && now.isAfter(coupon.getEndDate())) {
                return false;
            }
        }

        if (coupon.getValidDate() != null && now.isAfter(coupon.getValidDate())) {
            log.debug("过滤已过期的优惠券（validDate）, couponId={}, validDate={}, now={}",
                    coupon.getId(), coupon.getValidDate(), now);
            return false;
        }
        return true;
    }

    /**
     * /userOwned 排序：{@code amount} 仅用于比较「可否视为满足门槛」及估算优惠力度，不参与列表过滤。<br/>
     * 规则：{@code amount} 必须 &gt; 0；无门槛（最低消费为空或 ≤ 0）即视为门槛已满足（需金额大于 0）；有门槛时需 {@code amount ≥ 最低消费}。
     */
    private void sortOwnedCouponsForCheckout(List<LifeDiscountCouponVo> couponVos, BigDecimal amount) {
        if (couponVos == null || couponVos.size() <= 1) {
            return;
        }
        if (amount != null) {
            couponVos.sort((vo1, vo2) -> {
                boolean vo1CanUse = canUseCouponForCheckoutSort(vo1, amount);
                boolean vo2CanUse = canUseCouponForCheckoutSort(vo2, amount);

                if (vo1CanUse != vo2CanUse) {
                    return vo1CanUse ? -1 : 1;
                }

                BigDecimal discountAmount1 = calculateDiscountAmountForVO(vo1, amount);
                BigDecimal discountAmount2 = calculateDiscountAmountForVO(vo2, amount);
                int cmp = discountAmount2.compareTo(discountAmount1);
                if (cmp != 0) {
                    return cmp;
                }
                return compareUserCouponIdDesc(vo1, vo2);
            });
            return;
        }

        couponVos.sort((vo1, vo2) -> {
            BigDecimal nominalValue1 = vo1.getNominalValue() != null ? vo1.getNominalValue() : BigDecimal.ZERO;
            BigDecimal nominalValue2 = vo2.getNominalValue() != null ? vo2.getNominalValue() : BigDecimal.ZERO;
            int cmp = nominalValue2.compareTo(nominalValue1);
            if (cmp != 0) {
                return cmp;
            }
            return compareUserCouponIdDesc(vo1, vo2);
        });
    }

    private static int compareUserCouponIdDesc(LifeDiscountCouponVo vo1, LifeDiscountCouponVo vo2) {
        Integer id1 = vo1 != null ? vo1.getUserCouponId() : null;
        Integer id2 = vo2 != null ? vo2.getUserCouponId() : null;
        if (id1 == null && id2 == null) {
            return 0;
        }
        if (id1 == null) {
            return 1;
        }
        if (id2 == null) {
            return -1;
        }
        return id2.compareTo(id1);
    }

    /**
     * /userOwned 排序专用：不传金额或金额 ≤ 0 时一律视为不可用（排序靠后）。
     * 无门槛券：{@code minimumSpendingAmount == null || ≤ 0}，需当前 {@code amount &gt; 0}；
     * 有门槛券：需 {@code amount ≥ minimumSpendingAmount}。
     */
    private static boolean canUseCouponForCheckoutSort(LifeDiscountCouponVo vo, BigDecimal amount) {
        if (vo == null || amount == null || amount.compareTo(BigDecimal.ZERO) <= 0) {
            return false;
        }
        BigDecimal min = vo.getMinimumSpendingAmount();
        if (min == null || min.compareTo(BigDecimal.ZERO) <= 0) {
            return true;
        }
        return min.compareTo(amount) <= 0;
    }

    /**
     * 将优惠券实体转换为VO
     */
    private LifeDiscountCouponVo convertToVo(LifeDiscountCoupon coupon, LifeDiscountCouponUser userCoupon) {
        LifeDiscountCouponVo vo = new LifeDiscountCouponVo();
        vo.setId(coupon.getId());
        vo.setUserCouponId(userCoupon.getId());
        vo.setStoreId(coupon.getStoreId());
        vo.setUserId(String.valueOf(userCoupon.getUserId()));
        vo.setCouponId(coupon.getId());
        vo.setName(coupon.getName());
        vo.setNominalValue(coupon.getNominalValue());
        vo.setExpirationDate(coupon.getExpirationDate());
        vo.setStartDate(coupon.getStartDate());
        vo.setEndDate(coupon.getEndDate());
        vo.setSingleQty(coupon.getSingleQty());
        vo.setSupplementaryInstruction(coupon.getSupplementaryInstruction());
        vo.setGetStatus(coupon.getGetStatus());
        vo.setRestrictedQuantity(coupon.getRestrictedQuantity());
        vo.setMinimumSpendingAmount(coupon.getMinimumSpendingAmount());
        vo.setType(coupon.getType());
        vo.setAttentionCanReceived(coupon.getAttentionCanReceived());
        vo.setExpirationTime(userCoupon.getExpirationTime());
        vo.setCreatedTime(coupon.getCreatedTime());
        vo.setCouponType(coupon.getCouponType());
        vo.setDiscountRate(coupon.getDiscountRate());
        vo.setLongTermValid(coupon.getLongTermValid());
        vo.setUnlimitedQty(coupon.getUnlimitedQty());
        return vo;
    }

    /**
     * 计算优惠券的实际优惠金额（用于排序）
     * 根据优惠券类型（满减券或折扣券）计算实际优惠金额
     *
     * @param vo          优惠券VO
     * @param orderAmount 订单金额（用于计算折扣券的优惠金额）
     * @return 实际优惠金额
     */
    private BigDecimal calculateDiscountAmountForVO(LifeDiscountCouponVo vo, BigDecimal orderAmount) {
        if (vo == null) {
            return BigDecimal.ZERO;
        }

        Integer couponType = vo.getCouponType();
        BigDecimal discountAmount = BigDecimal.ZERO;

        if (couponType != null && couponType == 2) {
            // 折扣券：根据折扣率计算优惠金额
            // discountRate: 0-100，例如80表示8折，优惠金额 = 订单金额 * (100 - discountRate) / 100
            BigDecimal discountRate = vo.getDiscountRate();
            if (discountRate != null && discountRate.compareTo(BigDecimal.ZERO) > 0 
                    && discountRate.compareTo(new BigDecimal(100)) <= 0 && orderAmount != null 
                    && orderAmount.compareTo(BigDecimal.ZERO) > 0) {
                // 计算折扣后的金额
                BigDecimal discountedAmount = orderAmount.multiply(discountRate)
                        .divide(new BigDecimal(100), 2, BigDecimal.ROUND_HALF_UP);
                // 优惠金额 = 原价 - 折扣后价格
                discountAmount = orderAmount.subtract(discountedAmount);
            }
        } else {
            // 满减券（默认或couponType=1）：使用nominalValue
            discountAmount = vo.getNominalValue();
            if (discountAmount == null) {
                discountAmount = BigDecimal.ZERO;
            }
            // 优惠金额不能超过订单总金额
            if (orderAmount != null && discountAmount.compareTo(orderAmount) > 0) {
                discountAmount = orderAmount;
            }
        }

        return discountAmount;
    }
}
