package com.izouma.nineth.service;

import com.izouma.nineth.config.RedisKeys;
import com.izouma.nineth.domain.*;
import com.izouma.nineth.dto.PageQuery;
import com.izouma.nineth.dto.auction.AuctionRecordDTO;
import com.izouma.nineth.enums.AuctionOrderStatus;
import com.izouma.nineth.enums.AuctionPaymentType;
import com.izouma.nineth.enums.AuctionRecordType;
import com.izouma.nineth.enums.AuctionStatus;
import com.izouma.nineth.exception.BusinessException;
import com.izouma.nineth.repo.*;
import com.izouma.nineth.utils.JpaUtils;
import com.izouma.nineth.utils.SecurityUtils;
import lombok.AllArgsConstructor;
import org.apache.commons.lang3.ObjectUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

@Service
@AllArgsConstructor
public class AuctionRecordService {

    private AuctionRecordRepo             auctionRecordRepo;
    private AuctionActivityRepo           auctionActivityRepo;
    private AuctionOrderRepo              auctionOrderRepo;
    private RedisTemplate<String, Object> redisTemplate;
    private UserRepo                      userRepo;
    private UserBalanceRepo               userBalanceRepo;
    private SysConfigService              sysConfigService;

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

    public Page<AuctionRecordDTO> recordInfos(PageQuery pageQuery) {

        Page<AuctionRecord> records = auctionRecordRepo
                .findAll(JpaUtils.toSpecification(pageQuery, AuctionRecord.class), JpaUtils.toPageRequest(pageQuery));

        List<AuctionRecordDTO> auctionRecordDTOS = new ArrayList<>();
        records.getContent().forEach(record -> {
            AuctionActivity auctionActivity = auctionActivityRepo.findById(record.getAuctionId())
                    .orElse(null);
            if (auctionActivity == null) {
                return;
            }
            AuctionRecordDTO auctionRecordDTO = new AuctionRecordDTO();
            auctionRecordDTO.setAuctionId(record.getAuctionId());
            auctionRecordDTO.setAuctionPic(auctionActivity.getPic());
            auctionRecordDTO.setMinter(auctionActivity.getMinter());
            auctionRecordDTO.setBidderPrice(record.getBidderPrice());
            auctionRecordDTO.setActPurchasedId((auctionActivity.getPurchaserId()));
            auctionRecordDTO.setName(record.getName());
            auctionRecordDTO.setDeposit(auctionActivity.getDeposit());
            auctionRecordDTO.setEndTime(auctionActivity.getEndTime());
            auctionRecordDTO.setCreatedTime(record.getCreatedAt());
            auctionRecordDTO.setUserId(record.getUserId());
            auctionRecordDTO.setType(record.getType());
            auctionRecordDTO.setPurchased(record.isPurchased());
            auctionRecordDTO.setAuctionStatus(auctionActivity.getStatus());
            auctionRecordDTO.setAuctionType(auctionActivity.getAuctionType());
//            if (auctionActivity.getStatus().equals(AuctionStatus.PURCHASED) || auctionActivity.getStatus()
//                    .equals(AuctionStatus.FINISH)) {
//                if (auctionActivity.getRecordId() != null) {
//                    if (auctionActivity.getRecordId().equals(record.getId())) {
//                        auctionRecordDTO.setPurchased(true);
//                    }
//                }
//            }
            if (auctionRecordDTO.getType().equals(AuctionRecordType.DEPOSIT) || auctionRecordDTO.getType()
                    .equals(AuctionRecordType.BIDDER) || auctionRecordDTO.isPurchased()) {
                AuctionOrder auctionOrder = auctionOrderRepo.findFirstByAuctionRecordIdOrderByCreatedAt(record.getId());
                if (auctionOrder != null) {
                    auctionRecordDTO.setOrderId(auctionOrder.getId());
                    auctionRecordDTO.setOrderStatus(auctionOrder.getStatus());
                }
            }
            Set<AuctionOrderStatus> auctionOrderStatuses = new HashSet<>();
            auctionOrderStatuses.add(AuctionOrderStatus.NOT_PAID);
            auctionOrderStatuses.add(AuctionOrderStatus.CANCELLED);
            AuctionOrder depositOrder = auctionOrderRepo.findFirstByAuctionIdAndPaymentTypeAndStatusNotInAndUserIdOrderByIdDesc(record
                    .getAuctionId(), AuctionPaymentType.DEPOSIT, auctionOrderStatuses, SecurityUtils.getAuthenticatedUser()
                    .getId());
            if (depositOrder != null) {
                auctionRecordDTO.setDepositStatus(depositOrder.getStatus());
            } else {
                auctionRecordDTO.setDepositStatus(AuctionOrderStatus.FINISH);
            }
            auctionRecordDTOS.add(auctionRecordDTO);
        });
        return new PageImpl<>(auctionRecordDTOS, records.getPageable(), records.getTotalElements());
    }

    public List<AuctionRecordDTO> userRecord(Long userId, String type) {
        List<AuctionRecord> records = auctionRecordRepo.findByUserId(userId, type);
        List<AuctionRecordDTO> auctionRecordDTOS = new ArrayList<>();
        records.forEach(record -> {
            AuctionActivity auctionActivity = auctionActivityRepo.findById(record.getAuctionId())
                    .orElse(null);
            if (auctionActivity == null) {
                return;
            }
            AuctionRecordDTO auctionRecordDTO = new AuctionRecordDTO();
            BeanUtils.copyProperties(record, auctionRecordDTO);
            auctionRecordDTO.setAuctionPic(auctionActivity.getPic());
            auctionRecordDTO.setMinter(auctionActivity.getMinter());
            auctionRecordDTO.setAuctionPic(auctionActivity.getPic());
            auctionRecordDTO.setActPurchasedId((auctionActivity.getPurchaserId()));
            auctionRecordDTO.setDeposit(auctionActivity.getDeposit());
            auctionRecordDTO.setEndTime(auctionActivity.getEndTime());
            auctionRecordDTO.setAuctionType(auctionActivity.getAuctionType());
            auctionRecordDTO.setAuctionStatus(auctionActivity.getStatus());
            auctionRecordDTO.setCreatedTime(record.getCreatedAt());
//            if (auctionRecordDTO.getType().equals(AuctionRecordType.DEPOSIT) || auctionRecordDTO.isPurchased()) {
            AuctionOrder auctionOrder = auctionOrderRepo.findFirstByAuctionRecordIdOrderByIdDesc(record.getId());
            if (auctionOrder != null) {
                auctionRecordDTO.setOrderId(auctionOrder.getId());
                auctionRecordDTO.setOrderStatus(auctionOrder.getStatus());
            }
//            }
            Set<AuctionOrderStatus> auctionOrderStatuses = new HashSet<>();
            auctionOrderStatuses.add(AuctionOrderStatus.NOT_PAID);
            auctionOrderStatuses.add(AuctionOrderStatus.CANCELLED);
            AuctionOrder depositOrder = auctionOrderRepo.findFirstByAuctionIdAndPaymentTypeAndStatusNotInAndUserIdOrderByIdDesc(record
                    .getAuctionId(), AuctionPaymentType.DEPOSIT, auctionOrderStatuses, userId);
            if (depositOrder != null) {
                auctionRecordDTO.setDepositStatus(depositOrder.getStatus());
            } else {
                auctionRecordDTO.setDepositStatus(AuctionOrderStatus.FINISH);
            }
            auctionRecordDTOS.add(auctionRecordDTO);
        });
        return auctionRecordDTOS;
    }

    public AuctionRecord create(Long userId, Long auctionId, BigDecimal amount) {
        User user = userRepo.findById(userId).orElseThrow(new BusinessException("无用户"));

        //竞拍人绿魔卡余额限制
        BigDecimal minAmount = sysConfigService.getBigDecimal("auction_min_amount");
        if (!user.isWalletEnabled()) {
            throw new BusinessException("请开通绿魔卡，并充值" + minAmount + "元");
        } else {
            UserBalance userBalance = userBalanceRepo.findByUserId(user.getId()).orElse(new UserBalance(user.getId()));
            if (minAmount.compareTo(userBalance.getBalance()) > 0) {
                throw new BusinessException("绿魔卡余额不足" + minAmount + "元，请先充值");
            }
        }

        AuctionActivity auction = auctionActivityRepo.findById(auctionId)
                .orElseThrow(new BusinessException("暂无"));

        String status = (String) redisTemplate.opsForValue().get(RedisKeys.AUCTION_STATUS + auctionId);
        if (status == null)
            status = auction.getStatus().toString();
        switch (AuctionStatus.valueOf(status)) {
            case NOTSTARTED:
                throw new BusinessException("拍卖还未开始");
            case PURCHASED:
                throw new BusinessException("拍卖成交中");
            case PASS:
            case FINISH:
                throw new BusinessException("拍卖已结束");
        }

        AuctionRecord record = auctionRecordRepo.findTopByAuctionIdAndUserIdOrderByIdDesc(auctionId, userId);
        if (ObjectUtils.isEmpty(record)) {
            return auctionRecordRepo.save(AuctionRecord.builder()
                    .auctionId(auctionId)
                    .userId(userId)
                    .avatar(user.getAvatar())
                    .user(user.getNickname())
                    .name(auction.getName())
                    .auctionPic(null)
                    .bidderPrice(amount)
                    .purchased(false)
                    .type(AuctionRecordType.BIDDER)
                    .payDeposit(false)
                    .auctionType(auction.getAuctionType())
                    .build());
        }

        if (auction.getPurchasePrice() != null) {
            if (auction.getPurchasePrice().compareTo(amount) >= 0) {
                throw new BusinessException("出价低于当前竞拍价");
            }
        } else if (auction.getStartingPrice().compareTo(amount) >= 0) {

            throw new BusinessException("出价低于当前起拍价");
        }
        if (SecurityUtils.getAuthenticatedUser().getId().equals(auction.getPurchaserId())) {
            throw new BusinessException("请勿重复竞价");
        }
        AuctionRecord save = new AuctionRecord();
        BeanUtils.copyProperties(record, save);
        save.setId(null);
        save.setUser(SecurityUtils.getAuthenticatedUser().getNickname());
        save.setBidderPrice(amount);
        save.setType(AuctionRecordType.BIDDER);
        save = auctionRecordRepo.save(save);

        if (record.isPayDeposit()) {
            //保证金支付过，改成交价
            auction.setPurchasePrice(amount);
            auction.setPurchaser(SecurityUtils.getAuthenticatedUser().getNickname());
            auction.setPurchaserId(SecurityUtils.getAuthenticatedUser().getId());
            auction.setRecordId(save.getId());
            auction.setBids(auction.getBids() + 1);
            auctionActivityRepo.save(auction);
        }
        return save;
    }
}
