package com.starry.admin.modules.weichat.service;

import com.starry.admin.common.conf.ThreadLocalRequestDetail;
import com.starry.admin.common.exception.CustomException;
import com.starry.admin.modules.blindbox.mapper.BlindBoxRewardMapper;
import com.starry.admin.modules.blindbox.module.entity.BlindBoxConfigEntity;
import com.starry.admin.modules.blindbox.module.entity.BlindBoxRewardEntity;
import com.starry.admin.modules.blindbox.service.BlindBoxConfigService;
import com.starry.admin.modules.blindbox.service.BlindBoxService;
import com.starry.admin.modules.custom.module.entity.PlayCustomUserInfoEntity;
import com.starry.admin.modules.custom.service.IPlayCustomUserInfoService;
import com.starry.admin.modules.order.module.constant.OrderConstant;
import com.starry.admin.modules.order.module.constant.OrderConstant.OrderActor;
import com.starry.admin.modules.order.module.constant.OrderConstant.RewardType;
import com.starry.admin.modules.order.module.dto.CommodityInfo;
import com.starry.admin.modules.order.module.dto.OrderCreationContext;
import com.starry.admin.modules.order.module.dto.OrderPlacementCommand;
import com.starry.admin.modules.order.module.dto.OrderPlacementResult;
import com.starry.admin.modules.order.module.dto.PaymentInfo;
import com.starry.admin.modules.order.module.entity.PlayOrderInfoEntity;
import com.starry.admin.modules.order.service.IOrderLifecycleService;
import com.starry.admin.modules.order.service.IPlayOrderInfoService;
import com.starry.admin.modules.shop.mapper.PlayGiftInfoMapper;
import com.starry.admin.modules.shop.module.entity.PlayGiftInfoEntity;
import com.starry.admin.modules.weichat.entity.blindbox.BlindBoxPurchaseRequest;
import com.starry.admin.modules.weichat.entity.blindbox.BlindBoxPurchaseResult;
import com.starry.admin.modules.weichat.entity.blindbox.BlindBoxPurchaseResult.BlindBoxRewardInfo;
import com.starry.admin.modules.weichat.entity.blindbox.BlindBoxRewardView;
import com.starry.common.utils.IdUtils;
import java.math.BigDecimal;
import java.util.Collections;
import java.util.List;
import java.util.Objects;
import java.util.UUID;
import java.util.stream.Collectors;
import javax.annotation.Resource;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

@Service
public class WxBlindBoxOrderService {

    @Resource
    private BlindBoxConfigService blindBoxConfigService;

    @Resource
    private BlindBoxService blindBoxService;

    @Resource
    private IOrderLifecycleService orderLifecycleService;

    @Resource
    private IPlayOrderInfoService playOrderInfoService;

    @Resource
    private IPlayCustomUserInfoService customUserInfoService;

    @Resource
    private PlayGiftInfoMapper playGiftInfoMapper;

    @Resource
    private BlindBoxRewardMapper blindBoxRewardMapper;

    @Transactional(rollbackFor = Exception.class)
    public BlindBoxPurchaseResult purchase(BlindBoxPurchaseRequest request) {
        PlayCustomUserInfoEntity sessionUser = ThreadLocalRequestDetail.getCustomUserInfo();
        if (sessionUser == null || sessionUser.getId() == null) {
            throw new CustomException("用户未登录");
        }
        PlayCustomUserInfoEntity customer = customUserInfoService.selectById(sessionUser.getId());
        if (customer == null) {
            throw new CustomException("用户不存在");
        }

        BlindBoxConfigEntity config = blindBoxConfigService.requireById(request.getBlindBoxId());
        if (!Objects.equals(config.getTenantId(), customer.getTenantId())) {
            throw new CustomException("盲盒不存在或已下架");
        }
        if (!Objects.equals(config.getStatus(), 1)) {
            throw new CustomException("盲盒已下架");
        }

        BigDecimal boxPrice = Objects.requireNonNull(config.getPrice(), "盲盒价格未配置");
        if (boxPrice.compareTo(BigDecimal.ZERO) <= 0) {
            throw new CustomException("盲盒价格异常");
        }

        String orderId = IdUtils.getUuid();
        OrderCreationContext orderRequest = buildOrderRequest(orderId, request, customer, config, boxPrice);
        OrderPlacementResult result = orderLifecycleService.placeOrder(OrderPlacementCommand.builder()
                .orderContext(orderRequest)
                .balanceOperationAction("购买盲盒")
                .build());
        PlayOrderInfoEntity order = result.getOrder();

        BlindBoxRewardEntity reward = blindBoxService.drawReward(
                customer.getTenantId(),
                orderId,
                customer.getId(),
                config.getId(),
                UUID.randomUUID().toString());

        PlayGiftInfoEntity giftInfo = playGiftInfoMapper.selectById(reward.getRewardGiftId());

        return BlindBoxPurchaseResult.builder()
                .orderId(order.getId())
                .reward(buildRewardInfo(reward, config, giftInfo))
                .build();
    }

    public List<BlindBoxRewardView> listRewards(String tenantId, String customerId, String status) {
        return blindBoxService.listRewards(tenantId, customerId, status).stream()
                .map(this::toRewardView)
                .collect(Collectors.toList());
    }

    @Transactional(rollbackFor = Exception.class)
    public BlindBoxRewardView dispatchReward(String rewardId, String clerkId) {
        PlayCustomUserInfoEntity sessionUser = ThreadLocalRequestDetail.getCustomUserInfo();
        if (sessionUser == null || sessionUser.getId() == null) {
            throw new CustomException("用户未登录");
        }
        blindBoxService.dispatchReward(rewardId, clerkId, sessionUser.getId());
        BlindBoxRewardEntity updated = blindBoxRewardMapper.selectById(rewardId);
        if (updated == null) {
            throw new CustomException("盲盒奖励不存在");
        }
        return toRewardView(updated);
    }

    public BlindBoxRewardView toRewardView(BlindBoxRewardEntity reward) {
        BlindBoxConfigEntity config = blindBoxConfigService.getById(reward.getBlindBoxId());
        PlayGiftInfoEntity gift = playGiftInfoMapper.selectById(reward.getRewardGiftId());
        return BlindBoxRewardView.builder()
                .id(reward.getId())
                .blindBoxId(reward.getBlindBoxId())
                .blindBoxName(config != null ? config.getName() : null)
                .blindBoxCover(config != null ? config.getCoverUrl() : null)
                .rewardGiftId(reward.getRewardGiftId())
                .rewardGiftName(gift != null ? gift.getName() : reward.getRewardGiftId())
                .rewardGiftImage(gift != null ? gift.getUrl() : null)
                .rewardGiftPrice(reward.getRewardPrice())
                .boxPrice(reward.getBoxPrice())
                .expiresAt(reward.getExpiresAt())
                .status(reward.getStatus())
                .build();
    }

    private BlindBoxRewardInfo buildRewardInfo(
            BlindBoxRewardEntity reward,
            BlindBoxConfigEntity config,
            PlayGiftInfoEntity giftInfo) {
        return BlindBoxRewardInfo.builder()
                .rewardId(reward.getId())
                .blindBoxId(reward.getBlindBoxId())
                .blindBoxName(config != null ? config.getName() : null)
                .blindBoxCover(config != null ? config.getCoverUrl() : null)
                .rewardGiftId(reward.getRewardGiftId())
                .rewardGiftName(giftInfo != null ? giftInfo.getName() : reward.getRewardGiftId())
                .rewardGiftImage(giftInfo != null ? giftInfo.getUrl() : null)
                .rewardGiftPrice(reward.getRewardPrice())
                .boxPrice(reward.getBoxPrice())
                .expiresAt(reward.getExpiresAt())
                .status(reward.getStatus())
                .build();
    }

    private OrderCreationContext buildOrderRequest(
            String orderId,
            BlindBoxPurchaseRequest request,
            PlayCustomUserInfoEntity customer,
            BlindBoxConfigEntity config,
            BigDecimal boxPrice) {

        return OrderCreationContext.builder()
                .orderId(orderId)
                .orderNo(playOrderInfoService.getOrderNo())
                .orderStatus(OrderConstant.OrderStatus.COMPLETED)
                .orderType(OrderConstant.OrderType.BLIND_BOX_PURCHASE)
                .placeType(OrderConstant.PlaceType.REWARD)
                .rewardType(RewardType.GIFT)
                .isFirstOrder(false)
                .creatorActor(OrderActor.CUSTOMER)
                .creatorId(customer.getId())
                .commodityInfo(CommodityInfo.builder()
                        .commodityId(config.getId())
                        .commodityType(OrderConstant.CommodityType.GIFT)
                        .commodityPrice(config.getPrice())
                        .commodityName(config.getName())
                        .commodityNumber("1")
                        .serviceDuration("")
                        .build())
                .paymentInfo(PaymentInfo.builder()
                        .orderMoney(boxPrice)
                        .finalAmount(boxPrice)
                        .discountAmount(BigDecimal.ZERO)
                        .couponIds(Collections.emptyList())
                        .payMethod(OrderConstant.PayMethod.BALANCE.getCode())
                        .paymentSource(OrderConstant.PaymentSource.BALANCE)
                        .build())
                .purchaserBy(customer.getId())
                .acceptBy(request.getClerkId())
                .weiChatCode(request.getWeiChatCode())
                .remark(request.getRemark())
                .build();
    }
}
