package com.ylx.giftCard.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.ylx.common.core.domain.model.WxLoginUser;
import com.ylx.common.exception.ServiceException;
import com.ylx.common.utils.DateUtils;
import com.ylx.common.utils.SecurityUtils;
import com.ylx.common.weixinPay.enums.WxPayTypeEnum;
import com.ylx.common.weixinPay.service.WxPayV3Service;
import com.ylx.giftCard.domain.GiftCard;
import com.ylx.giftCard.domain.GiftCardOrder;
import com.ylx.giftCard.domain.dto.GiftCardManageQueryDTO;
import com.ylx.giftCard.domain.dto.GiftCardManageSaveDTO;
import com.ylx.giftCard.domain.dto.GiftCardManageUpdateDTO;
import com.ylx.giftCard.domain.dto.GiftCardPublishStatusDTO;
import com.ylx.giftCard.domain.dto.GiftCardPurchaseDTO;
import com.ylx.giftCard.domain.vo.GiftCardDetailVO;
import com.ylx.giftCard.domain.vo.GiftCardManageDetailVO;
import com.ylx.giftCard.domain.vo.GiftCardManageExportVO;
import com.ylx.giftCard.domain.vo.GiftCardManagePageVO;
import com.ylx.giftCard.domain.vo.GiftCardVO;
import com.ylx.giftCard.mapper.GiftCardMapper;
import com.ylx.giftCard.service.IGiftCardOrderService;
import com.ylx.giftCard.service.IGiftCardService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

@Slf4j
@Service
public class GiftCardServiceImpl extends ServiceImpl<GiftCardMapper, GiftCard> implements IGiftCardService {

    @Resource
    private IGiftCardOrderService giftCardOrderService;
    @Resource
    private WxPayV3Service wxPayV3Service;

    private static final int NOT_DELETE = 0;
    private static final int PUBLISHED = 1;
    private static final int UNPUBLISHED = 0;
    private static final int DELETE = 1;

    @Override
    public Page<GiftCardVO> getGiftCardPage(Page<GiftCard> page) {

        LambdaQueryWrapper<GiftCard> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(GiftCard::getIsDelete, NOT_DELETE);
        wrapper.eq(GiftCard::getIsPublished, PUBLISHED);
        wrapper.orderByDesc(GiftCard::getCreateTime);

        Page<GiftCard> giftCardPage = this.baseMapper.selectPage(page, wrapper);
        Page<GiftCardVO> pageData = new Page<>(
                giftCardPage.getCurrent(),
                giftCardPage.getSize(),
                giftCardPage.getTotal()
        );

        if (CollectionUtil.isNotEmpty(giftCardPage.getRecords())) {
            List<GiftCardVO> voList = giftCardPage.getRecords().stream()
                    .map(GiftCardVO::new)
                    .collect(Collectors.toList());
            pageData.setRecords(voList);
        }

        return pageData;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Map<String, Object> purchaseGiftCard(GiftCardPurchaseDTO dto) {

        // 1. 获取当前用户
        WxLoginUser wxLoginUser = SecurityUtils.getWxLoginUser();
        if (ObjectUtil.isNull(wxLoginUser)) {
            log.warn("用户未登录，无法创建订单");
            throw new ServiceException("用户未登录");
        }

        Long id = dto.getId();
        Integer quantity = dto.getQuantity();
        String merchantId = dto.getMerchantId();

        // 2. 查询并校验购物卡
        GiftCard card = this.getById(id);
        validateGiftCard(card, quantity);

        // 3. 乐观锁扣减库存（增加状态校验，防止无效更新）
        int rowsAffected = deductStockOptimisticLock(card.getId(), dto.getQuantity());
        if (rowsAffected <= 0) {
            log.warn("购买失败，库存不足或商品不存在，购物卡ID: {}", id);
            throw new ServiceException("库存不足或商品状态异常");
        }

        log.info("购买成功，购物卡ID: {}, 数量: {}", id, quantity);

        // 4. 创建订单
        GiftCardOrder order = this.giftCardOrderService.buildOrder(card, quantity, merchantId, wxLoginUser);
        if(ObjectUtil.isNull(order)){
            log.warn("购物卡订单创建失败，购物卡ID: {}，下单人ID: {}", card.getId(), wxLoginUser.getId());
            throw new ServiceException("购物卡订单创建失败");
        }

        log.info("购物卡订单创建，购物卡ID: {}, 订单编号: {}", id, order.getOrderNo());

        //  5. 调用微信支付
        return createWxPayOrder(order, wxLoginUser);
    }

    @Override
    public GiftCardDetailVO getGiftCardDetail(Long id) {

        LambdaQueryWrapper<GiftCard> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(GiftCard::getId, id)
                .eq(GiftCard::getIsDelete, NOT_DELETE)
                .eq(GiftCard::getIsPublished, PUBLISHED);

        GiftCard card = this.getOne(wrapper);
        if (ObjectUtil.isNull(card)) {
            return null;
        }

        GiftCardDetailVO vo = new GiftCardDetailVO();
        BeanUtil.copyProperties(card, vo);
        return vo;
    }

    @Override
    public Page<GiftCardManagePageVO> getManagePage(Page<GiftCard> page, GiftCardManageQueryDTO dto) {
        Page<GiftCard> pageParam = ObjectUtil.isNull(page) ? new Page<>(1, 10) : page;
        LambdaQueryWrapper<GiftCard> wrapper = buildManageQueryWrapper(dto);

        Page<GiftCard> entityPage = this.baseMapper.selectPage(pageParam, wrapper);
        Page<GiftCardManagePageVO> pageData = new Page<>(entityPage.getCurrent(), entityPage.getSize(), entityPage.getTotal());
        pageData.setPages(entityPage.getPages());
        if (CollectionUtil.isNotEmpty(entityPage.getRecords())) {
            pageData.setRecords(entityPage.getRecords().stream()
                    .map(this::toManagePageVO)
                    .collect(Collectors.toList()));
        }
        return pageData;
    }

    @Override
    public List<GiftCardManageExportVO> getManageExportList(GiftCardManageQueryDTO dto) {
        GiftCardManageQueryDTO query = ObjectUtil.isNull(dto) ? new GiftCardManageQueryDTO() : dto;
        checkCreateDateRange(query.getBeginCreateDate(), query.getEndCreateDate());
        if (StrUtil.isNotBlank(query.getName())) {
            query.setName(StrUtil.trim(query.getName()));
        }
        List<GiftCard> entityList = this.baseMapper.selectManageList(
                query,
                toStartDate(query.getBeginCreateDate()),
                toEndDate(query.getEndCreateDate())
        );
        return entityList.stream().map(this::toManageExportVO).collect(Collectors.toList());
    }

    @Override
    public GiftCardManageDetailVO getManageDetail(Long id) {
        GiftCard card = getActiveGiftCard(id);
        GiftCardManageDetailVO vo = new GiftCardManageDetailVO();
        BeanUtil.copyProperties(card, vo);
        return vo;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void addGiftCard(GiftCardManageSaveDTO dto) {
        checkSaveParam(dto);

        GiftCard entity = new GiftCard();
        fillGiftCard(entity, dto, normalizePublishStatus(dto.getIsPublished(), UNPUBLISHED));
        entity.setId(null);
        entity.setSales(0);
        entity.setCreateBy(SecurityUtils.getUsername());
        entity.setCreateTime(DateUtils.getNowDate());
        entity.setUpdateBy(SecurityUtils.getUsername());
        entity.setUpdateTime(DateUtils.getNowDate());

        int insertResult = this.baseMapper.insert(entity);
        if (insertResult <= 0) {
            throw new ServiceException("新增购物卡失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updateGiftCard(GiftCardManageUpdateDTO dto) {
        if (ObjectUtil.isNull(dto) || ObjectUtil.isNull(dto.getId())) {
            throw new ServiceException("购物卡ID不能为空");
        }
        checkSaveParam(dto);

        GiftCard entity = getActiveGiftCard(dto.getId());
        Integer publishStatus = normalizePublishStatus(dto.getIsPublished(), entity.getIsPublished());
        fillGiftCard(entity, dto, publishStatus);
        entity.setUpdateBy(SecurityUtils.getUsername());
        entity.setUpdateTime(DateUtils.getNowDate());

        int updateResult = this.baseMapper.updateById(entity);
        if (updateResult <= 0) {
            throw new ServiceException("编辑购物卡失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void updatePublishStatus(GiftCardPublishStatusDTO dto) {
        if (ObjectUtil.isNull(dto) || ObjectUtil.isNull(dto.getId())) {
            throw new ServiceException("购物卡ID不能为空");
        }
        Integer publishStatus = normalizePublishStatus(dto.getIsPublished(), null);
        GiftCard entity = getActiveGiftCard(dto.getId());
        entity.setIsPublished(publishStatus);
        entity.setUpdateBy(SecurityUtils.getUsername());
        entity.setUpdateTime(DateUtils.getNowDate());

        int updateResult = this.baseMapper.updateById(entity);
        if (updateResult <= 0) {
            throw new ServiceException("修改购物卡上架状态失败");
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void deleteGiftCard(Long id) {
        int deleteResult = this.baseMapper.deleteById(id);
        if (deleteResult <= 0) {
            throw new ServiceException("删除购物卡失败");
        }
    }

    /**
     * 校验购物卡有效性
     */
    private void validateGiftCard(GiftCard card, Integer quantity) {
        if (ObjectUtil.isNull(card)) {
            throw new ServiceException("商品不存在");
        }
        if (card.getIsDelete() != NOT_DELETE) {
            log.warn("购买失败，购物卡已删除，ID: {}", card.getId());
            throw new ServiceException("购物卡已删除");
        }
        if (card.getIsPublished() != PUBLISHED) {
            log.warn("购买失败，购物卡未上架，ID: {}", card.getId());
            throw new ServiceException("购物卡未上架");
        }
        if (card.getStock() < quantity) {
            log.warn("购买失败，库存不足，ID: {}，库存: {}，需求数量: {}", card.getId(), card.getStock(), quantity);
            throw new ServiceException("库存不足");
        }

    }

    /**
     * 乐观锁扣减库存（增加状态条件，确保只更新有效记录）
     */
    private int deductStockOptimisticLock(Long cardId, Integer quantity) {
        LambdaUpdateWrapper<GiftCard> wrapper = new LambdaUpdateWrapper<>();
        wrapper.eq(GiftCard::getId, cardId)
                .eq(GiftCard::getIsDelete, NOT_DELETE)
                .eq(GiftCard::getIsPublished, PUBLISHED)
                .ge(GiftCard::getStock, quantity) // 库存充足时才更新
                .setSql("stock = stock - " + quantity + ", sales = sales + " + quantity);
        return baseMapper.update(null, wrapper);
    }

    /**
     * 补偿回滚库存
     */
    private void recoverStock(Long cardId, Integer num) {
        GiftCard updateEntity = new GiftCard();
        LambdaUpdateWrapper<GiftCard> updateWrapper = new LambdaUpdateWrapper<>();
        updateWrapper.eq(GiftCard::getId, cardId)
                .eq(GiftCard::getIsDelete, NOT_DELETE);
        updateWrapper.setSql("stock = stock + #{num}, sales = sales - #{num}");
        // 数据放到实体里
        updateEntity.setStock(num);
        baseMapper.update(updateEntity, updateWrapper);
    }

    /**
     * 创建微信支付订单（事务外执行，减少事务时长）
     */
    private Map<String, Object> createWxPayOrder(GiftCardOrder order, WxLoginUser wxLoginUser) {
        try {
            return wxPayV3Service.createV3JsapiOrder(
                    order.getOrderNo(),
                    order.getPayAmount(),
                    "购物卡购买",
                    wxLoginUser.getCOpenid(),
                    WxPayTypeEnum.GIFT_CARD.getCode()
            );
        } catch (Exception e) {
            log.error("微信支付下单失败，订单号: {}", order.getOrderNo(), e);
            // 支付失败：恢复库存、修改订单为取消
            recoverStock(order.getGiftCardId(), order.getPurchaseQuantity());
            this.giftCardOrderService.cancelOrder(order.getId());
            throw new ServiceException("支付服务异常，请稍后重试");
        }
    }

    private GiftCard getActiveGiftCard(Long id) {
        if (ObjectUtil.isNull(id)) {
            throw new ServiceException("购物卡ID不能为空");
        }
        if (id <= 0) {
            throw new ServiceException("购物卡ID不正确");
        }

        LambdaQueryWrapper<GiftCard> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(GiftCard::getId, id).eq(GiftCard::getIsDelete, NOT_DELETE);
        GiftCard entity = this.baseMapper.selectOne(wrapper);
        if (ObjectUtil.isNull(entity)) {
            throw new ServiceException("购物卡不存在或已删除");
        }
        return entity;
    }

    private void checkSaveParam(GiftCardManageSaveDTO dto) {
        if (ObjectUtil.isNull(dto)) {
            throw new ServiceException("购物卡参数不能为空");
        }
        if (StrUtil.isBlank(dto.getName())) {
            throw new ServiceException("购物卡名称不能为空");
        }
        if (StrUtil.length(StrUtil.trim(dto.getName())) > 20) {
            throw new ServiceException("购物卡名称不能超过20个字符");
        }
        if (StrUtil.isBlank(dto.getImageUrl())) {
            throw new ServiceException("图片不能为空");
        }
        if (ObjectUtil.isNull(dto.getAmount()) || dto.getAmount().signum() <= 0) {
            throw new ServiceException("购物卡金额必须大于0");
        }
        if (ObjectUtil.isNull(dto.getCommissionRate())
                || dto.getCommissionRate().signum() < 0
                || dto.getCommissionRate().compareTo(new BigDecimal("100")) > 0) {
            throw new ServiceException("商户提成比例必须在0到100之间");
        }
        if (ObjectUtil.isNull(dto.getStock()) || dto.getStock() < 0) {
            throw new ServiceException("库存不能小于0");
        }
        if (ObjectUtil.isNull(dto.getValidStartDate()) || ObjectUtil.isNull(dto.getValidEndDate())) {
            throw new ServiceException("有效期不能为空");
        }
        if (dto.getValidStartDate().isAfter(dto.getValidEndDate())) {
            throw new ServiceException("有效期开始日期不能晚于结束日期");
        }
    }

    private void checkCreateDateRange(LocalDate beginDate, LocalDate endDate) {
        if (ObjectUtil.isNotNull(beginDate) && ObjectUtil.isNotNull(endDate) && beginDate.isAfter(endDate)) {
            throw new ServiceException("创建开始日期不能晚于结束日期");
        }
    }

    private LambdaQueryWrapper<GiftCard> buildManageQueryWrapper(GiftCardManageQueryDTO dto) {
        GiftCardManageQueryDTO query = ObjectUtil.isNull(dto) ? new GiftCardManageQueryDTO() : dto;
        checkCreateDateRange(query.getBeginCreateDate(), query.getEndCreateDate());

        LambdaQueryWrapper<GiftCard> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(GiftCard::getIsDelete, NOT_DELETE)
                .like(StrUtil.isNotBlank(query.getName()), GiftCard::getName, StrUtil.trim(query.getName()))
                .eq(ObjectUtil.isNotNull(query.getIsPublished()), GiftCard::getIsPublished, query.getIsPublished())
                .ge(ObjectUtil.isNotNull(query.getBeginCreateDate()), GiftCard::getCreateTime, toStartDate(query.getBeginCreateDate()))
                .le(ObjectUtil.isNotNull(query.getEndCreateDate()), GiftCard::getCreateTime, toEndDate(query.getEndCreateDate()))
                .orderByDesc(GiftCard::getCreateTime)
                .orderByDesc(GiftCard::getId);
        return wrapper;
    }

    /**
     * 填充购物卡实体
     * @param entity
     * @param dto
     * @param publishStatus
     */
    private void fillGiftCard(GiftCard entity, GiftCardManageSaveDTO dto, Integer publishStatus) {
        entity.setMerchantId(StrUtil.trim(dto.getMerchantId()));
        entity.setName(StrUtil.trim(dto.getName()));
        entity.setImageUrl(StrUtil.trim(dto.getImageUrl()));
        entity.setAmount(dto.getAmount());
        entity.setCommissionRate(dto.getCommissionRate());
        entity.setStock(dto.getStock());
        entity.setValidStartDate(dto.getValidStartDate());
        entity.setValidEndDate(dto.getValidEndDate());
        entity.setDescription(dto.getDescription());
        entity.setIsPublished(publishStatus);
    }

    /**
     * 规范化上架状态值
     * @param value
     * @param defaultValue
     * @return Integer
     */
    private Integer normalizePublishStatus(Integer value, Integer defaultValue) {
        if (ObjectUtil.isNull(value)) {
            if (ObjectUtil.isNull(defaultValue)) {
                throw new ServiceException("上架状态不能为空");
            }
            return defaultValue;
        }
        if (value == UNPUBLISHED || value == PUBLISHED) {
            return value;
        }
        throw new ServiceException("上架状态值不正确");
    }

    private GiftCardManagePageVO toManagePageVO(GiftCard entity) {
        GiftCardManagePageVO vo = new GiftCardManagePageVO();
        BeanUtil.copyProperties(entity, vo);
        return vo;
    }

    private GiftCardManageExportVO toManageExportVO(GiftCard entity) {
        GiftCardManageExportVO vo = new GiftCardManageExportVO();
        BeanUtil.copyProperties(entity, vo);
        return vo;
    }

    private Date toStartDate(LocalDate date) {
        if (ObjectUtil.isNull(date)) {
            return null;
        }
        return Date.from(date.atStartOfDay(ZoneId.systemDefault()).toInstant());
    }

    private Date toEndDate(LocalDate date) {
        if (ObjectUtil.isNull(date)) {
            return null;
        }
        return Date.from(date.plusDays(1).atStartOfDay(ZoneId.systemDefault()).minusNanos(1).toInstant());
    }

}
