package com.izouma.nineth.service;

import com.izouma.nineth.TokenHistory;
import com.izouma.nineth.domain.*;
import com.izouma.nineth.dto.PageQuery;
import com.izouma.nineth.enums.AirDropType;
import com.izouma.nineth.enums.CollectionType;
import com.izouma.nineth.exception.BusinessException;
import com.izouma.nineth.repo.*;
import com.izouma.nineth.utils.JpaUtils;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.stereotype.Service;

import java.time.LocalDateTime;
import java.util.List;

@Service
@AllArgsConstructor
@Slf4j
public class AirDropService {

    private AirDropRepo       airDropRepo;
    private CouponRepo        couponRepo;
    private UserCouponRepo    userCouponRepo;
    private CollectionRepo    collectionRepo;
    private UserRepo          userRepo;
    private AssetService      assetService;
    private CollectionService collectionService;
    private ShowroomService   showroomService;
    private TokenHistoryRepo  tokenHistoryRepo;
    private AssetRepo         assetRepo;

    public Page<AirDrop> all(PageQuery pageQuery) {
        return airDropRepo.findAll(JpaUtils.toSpecification(pageQuery, AirDrop.class), JpaUtils.toPageRequest(pageQuery));
    }

    public AirDrop create(AirDrop record) {
        if (AirDropType.coupon == record.getType()) {
            Coupon coupon = couponRepo.findById(record.getCouponId()).orElseThrow(new BusinessException("兑换券不存在"));
            record.getUserIds().stream().parallel().forEach(userId -> {
                UserCoupon userCoupon = new UserCoupon();
                BeanUtils.copyProperties(coupon, userCoupon);
                userCoupon.setId(null);
                userCoupon.setCouponId(coupon.getId());
                userCoupon.setUserId(userId);
                userCouponRepo.save(userCoupon);
            });
        } else {
            Collection collection = collectionRepo.findById(record.getCollectionId())
                    .orElseThrow(new BusinessException("藏品不存在"));
            if (collection.isSalable()) {
                throw new BusinessException("请先设置藏品为不可购买");
            }
            if (!record.isIgnoreStockCheck() && collection.getStock() < record.getUserIds().size()) {
                throw new BusinessException("藏品库存不足");
            }
            List<User> users = userRepo.findByIdInAndDelFalse(record.getUserIds());
            for (User user : users) {
                try {
                    if (collection.getType() == CollectionType.BLIND_BOX) {
                        BlindBoxItem winItem = collectionService.draw(collection.getId());
                        if (record.isSimulateOrder()) {
                            assetService.createAsset(winItem, user, 0L, collection.getPrice(), "出售",
                                    winItem.getTotal() > 1 ? collectionService.getNextNumber(winItem.getCollectionId()) : null,
                                    collection.getHoldDays());
                        } else {
                            assetService.createAsset(winItem, user, null, null, "空投",
                                    collectionService.getNextNumber(winItem.getCollectionId()), collection.getHoldDays());
                        }
                    } else {
                        Asset asset = new Asset();
                        if (record.isSimulateOrder()) {
                            assetService.createAsset(collection, user, 0L, collection.getPrice(), "出售",
                                    collection.getTotal() > 1 ? collectionService.getNextNumber(collection.getId()) : null);
                        } else {
                            asset = assetService.createAsset(collection, user, null, null, "空投", collectionService.getNextNumber(collection.getId()));
                        }
                        if (collection.getType() == CollectionType.SHOWROOM) {
                            showroomService.save(asset);
                        }
                    }
                    collectionService.decreaseStock(collection.getId(), 1);
                    collectionService.increaseSale(collection.getId(), 1);
                } catch (Exception e) {
                    log.error("空投出错", e);
                }
            }
        }
        return airDropRepo.save(record);
    }

    public void drop(Long collectionId, Long userId, int num, LocalDateTime time) {
        Collection collection = collectionRepo.findById(collectionId)
                .orElseThrow(new BusinessException("藏品不存在"));
        User user = userRepo.findById(userId).orElseThrow(new BusinessException("用户不存在"));
        try {
            for (int i = 0; i < num; i++) {
                Asset asset;
                if (collection.getType() == CollectionType.BLIND_BOX) {
                    BlindBoxItem winItem = collectionService.draw(collection.getId());
                    asset = assetService.createAsset(winItem, user, 0L, collection.getPrice(), "出售",
                            winItem.getTotal() > 1 ? collectionService.getNextNumber(winItem.getCollectionId()) : null,
                            collection.getHoldDays());
                } else {
                    asset = assetService.createAsset(collection, user, 0L, collection.getPrice(), "出售",
                            collection.getTotal() > 1 ? collectionService.getNextNumber(collection.getId()) : null);
                }
                assetRepo.flush();
                tokenHistoryRepo.flush();

                asset.setCreatedAt(time.plusSeconds((long) (Math.random() * 120)));
                assetRepo.save(asset);

                for (TokenHistory tokenHistory : tokenHistoryRepo.findByTokenIdOrderByCreatedAtDesc(asset.getTokenId())) {
                    tokenHistory.setCreatedAt(asset.getCreatedAt());
                    tokenHistoryRepo.save(tokenHistory);
                }
            }
        } catch (Exception e) {
            log.error("空投出错", e);
        }
    }
}
