package com.izouma.nineth.service;

import com.alibaba.fastjson.JSONObject;
import com.github.binarywang.wxpay.exception.WxPayException;
import com.huifu.adapay.core.exception.BaseAdaPayException;
import com.huifu.adapay.model.Payment;
import com.izouma.nineth.ApplicationTests;
import com.izouma.nineth.TokenHistory;
import com.izouma.nineth.domain.Collection;
import com.izouma.nineth.domain.*;
import com.izouma.nineth.dto.UserBankCard;
import com.izouma.nineth.enums.*;
import com.izouma.nineth.event.OrderNotifyEvent;
import com.izouma.nineth.exception.BusinessException;
import com.izouma.nineth.repo.*;
import com.izouma.nineth.utils.FileUtils;
import com.izouma.nineth.utils.SnowflakeIdWorker;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections.MapUtils;
import org.apache.rocketmq.spring.core.RocketMQTemplate;
import org.junit.Test;
import org.springframework.beans.factory.annotation.Autowired;

import java.io.IOException;
import java.math.BigDecimal;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.*;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.ForkJoinPool;
import java.util.stream.Collectors;

@Slf4j
public class OrderServiceTest extends ApplicationTests {
    @Autowired
    private OrderService       orderService;
    @Autowired
    private OrderRepo          orderRepo;
    @Autowired
    private AssetRepo          assetRepo;
    @Autowired
    private TokenHistoryRepo   tokenHistoryRepo;
    @Autowired
    private AssetService       assetService;
    @Autowired
    private CollectionRepo     collectionRepo;
    @Autowired
    private UserRepo           userRepo;
    @Autowired
    private IdentityAuthRepo   identityAuthRepo;
    @Autowired
    private UserBankCardRepo   userBankCardRepo;
    @Autowired
    private CollectionService  collectionService;
    @Autowired
    private BlindBoxItemRepo   blindBoxItemRepo;
    @Autowired
    private SnowflakeIdWorker  snowflakeIdWorker;
    @Autowired
    private ErrorOrderRepo     errorOrderRepo;
    @Autowired
    private RocketMQTemplate   rocketMQTemplate;
    @Autowired
    private SandPayService     sandPayService;
    @Autowired
    private UserBalanceService userBalanceService;
    @Autowired
    private BalanceRecordRepo  balanceRecordRepo;
    @Autowired
    private UserBalanceRepo    userBalanceRepo;


    @Test
    public void create() {
        Order order = new Order();
        order.setId(1234L);
        orderRepo.save(order);

        assert orderRepo.findById(1234L).orElse(null) != null;
    }

    @Test
    public void setNumber() {
        orderService.setNumber();
    }

    @Test
    public void setSales() {
        orderService.setSales();
    }

    @Test
    public void commission() {
        orderService.commission(orderRepo.findById(4437L).get());
    }

    @Test
    public void refund() throws WxPayException {
    }

    @Test
    public void cancel() {
        orderService.cancel(6721L);
    }

    @Test
    public void fixNotPaid() throws BaseAdaPayException {
        List<Order> errOrders = new ArrayList<>();
        orderRepo.findByStatus(OrderStatus.FINISH).stream().parallel().forEach(order -> {
            if (order.getCreatedAt().isAfter(LocalDateTime.of(2021, 11, 30, 1, 1))) {
                try {
                    Map<String, Object> res = Payment.query(order.getTransactionId());
                    String status = MapUtils.getString(res, "status");
                    String errMsg = MapUtils.getString(res, "error_msg");
                    if (!"succeeded".equals(status) && !"对应支付记录不存在".equals(errMsg)) {
                        System.out.println(order.getId());
                        errOrders.add(order);
                    }
                } catch (Exception e) {
                }
            }
        });

        System.out.println(errOrders.stream().map(o -> o.getId().toString()).collect(Collectors.joining(",")));


        for (Order errOrder : errOrders) {
            Collection collection = collectionRepo.findById(errOrder.getCollectionId()).orElse(null);
            if (collection == null) continue;
            List<Asset> assets = assetRepo.findByOrderId(errOrder.getId());
            for (Asset asset : assets) {
                if (asset.getStatus() == AssetStatus.NORMAL) {
                    if (asset.isPublicShow()) {
                        assetService.cancelPublic(asset);
                    }
                    tokenHistoryRepo.deleteByTokenId(asset.getTokenId());
                    assetRepo.delete(asset);
                }
            }
            orderRepo.delete(errOrder);
            collectionService.increaseStock(collection.getId(), 1);
            collectionService.decreaseSale(collection.getId(), -1);
        }
    }

    @Test
    public void fixTokenHistory() {
        for (TokenHistory tokenHistory : tokenHistoryRepo.findError()) {
            List<Asset> assets = assetRepo.findByTokenIdOrderByCreatedAt(tokenHistory.getTokenId());
            if (assets.size() == 2) {
                userRepo.findById(assets.get(0).getUserId()).ifPresent(fromUser -> {
                    tokenHistory.setFromUserId(assets.get(0).getUserId());
                    tokenHistory.setFromUser(fromUser.getNickname());
                    tokenHistory.setFromAvatar(fromUser.getAvatar());
                    tokenHistoryRepo.save(tokenHistory);
                });
            }
        }
    }

    @Test
    public void fixPay() {
        String s = "\n订单ID\t金额\t手续费\t版税\t收款用户ID\t收款人\t银行卡号\t银行";
        for (Long orderId : new Long[]{5417L, 5919L, 5923L, 8166L}) {
            try {
                Order order = orderRepo.findById(orderId).get();
                List<Asset> assets = assetRepo.findByTokenIdOrderByCreatedAt(assetRepo.findById(order.getAssetId())
                        .get()
                        .getTokenId());
                Asset asset = assets.stream().filter(a -> a.getStatus() == AssetStatus.TRANSFERRED).findAny().get();
                User user = userRepo.findById(asset.getUserId()).get();
                Optional<IdentityAuth> identityAuth = identityAuthRepo.findByUserIdAndDelFalse(user.getId()).stream()
                        .filter(i -> i.getStatus() == AuthStatus.SUCCESS)
                        .findAny();
                Optional<UserBankCard> bankCard = userBankCardRepo.findByUserId(user.getId()).stream().findAny();
                s += "\n"
                        + orderId + "\t"
                        + order.getTotalPrice().subtract(order.getGasPrice()) + "\t"
                        + order.getServiceCharge() + "\t"
                        + order.getRoyalties() + "\t"
                        + user.getId() + "\t"
                        + identityAuth.map(IdentityAuth::getRealName).orElse("") + "\t"
                        + bankCard.map(UserBankCard::getBankNo).orElse("") + "\t"
                        + bankCard.map(UserBankCard::getBankName).orElse("");
            } catch (Exception e) {

            }

        }
        log.info(s);
    }

    @Test
    public void consignmentFix() throws IOException {
        String s = FileUtils.readFile("/Users/drew/Downloads/app.log").replaceAll("</p>\n", "</p>");
        String[] arr = s.split("\n");
        for (int i = 0; i < arr.length; i++) {
            if (arr[i].contains("insert into collection_info")) {
//                arr[i][2]
            }
        }
    }

    @Test
    public void removeDuplicate() {
        List<Long> ids = new ArrayList<>();
        orderRepo.findByCollectionId(8012L).stream()
                .filter(o -> o.getStatus() == OrderStatus.FINISH || o.getStatus() == OrderStatus.PROCESSING)
                .parallel().forEach(order -> {
                    List<Asset> assets = assetRepo.findByOrderId(order.getId());
                    if (assets.size() > 1) {
                        assets.sort(Comparator.comparing(Asset::getCreatedAt));
                        for (int i = 1; i < assets.size(); i++) {
                            assetRepo.delete(assets.get(i));
                            tokenHistoryRepo.deleteByTokenId(assets.get(i).getTokenId());
                            if (assets.get(i).getPublicCollectionId() != null) {
                                collectionRepo.findById(assets.get(i).getPublicCollectionId()).ifPresent(c -> {
                                    collectionRepo.delete(c);
                                });
                            }
                        }
                        ids.add(order.getId());
                    }
                });
        System.out.println(ids);
    }

    @Test
    public void setNumber1() {
        final int[] number = {1};
        orderRepo.findByCollectionId(8012L).stream()
                .filter(o -> o.getStatus() == OrderStatus.FINISH || o.getStatus() == OrderStatus.PROCESSING)
                .sorted(Comparator.comparing(Order::getCreatedAt))
                .forEach(order -> {
                    Asset asset = assetRepo.findByOrderId(order.getId()).get(0);
                    asset.setNumber(number[0]);
                    assetRepo.save(asset);
                    if (asset.getPublicCollectionId() != null) {
                        collectionRepo.findById(asset.getPublicCollectionId()).ifPresent(c -> {
                            c.setNumber(asset.getNumber());
                            collectionRepo.save(c);
                        });
                    }
                    number[0]++;
                });

        assetRepo.findByCollectionId(8012L).stream().parallel().forEach(asset -> {

        });

    }


    @Test
    public void asdf() {
        orderRepo.findByCollectionId(1226466L).stream().filter(o -> o.getStatus() == OrderStatus.FINISH).parallel()
                .forEach(order -> {
                    List<Asset> assets = assetRepo.findByOrderId(order.getId());
                    if (assets.size() > 1) {
                        for (int i = 1; i < assets.size(); i++) {
                            assetRepo.delete(assets.get(i));
                        }
                    }
                });
    }

    @Test
    public void test1() {
        orderService.queryCreateOrder("1234");
    }

    @Test
    public void test2() {
        System.out.println(orderRepo.countByUserIdAndCollectionIdAndVipTrueAndStatusIn(9850L, 196308L,
                Arrays.asList(OrderStatus.FINISH, OrderStatus.NOT_PAID, OrderStatus.PROCESSING)));
    }

    @Test
    public void calcSettle() {
    }

    @Test
    public void transferAsset() {
        Order order = orderRepo.findById(965655752003829760L).orElseThrow(new BusinessException("订单"));
        Asset asset = assetRepo.findById(order.getAssetId()).orElseThrow(new BusinessException("无"));
        User user = userRepo.findById(order.getUserId()).orElseThrow(new BusinessException("暂无"));
        if (asset.getStatus() == AssetStatus.TRADING) {
            assetService.transfer(asset, order.getPrice(), user, TransferReason.TRANSFER, order.getId());
        }
    }

    @Test
    public void fixCancel() {
        errorOrderRepo.findAll().stream().filter(o ->
                        "状态错误 CANCELLED".equals(o.getErrorMessage()) &&
                                o.getCreatedAt().isAfter(LocalDate.of(2022, 05, 13).atStartOfDay()))
                .forEach(errorOrder -> {
                    Order order = orderRepo.findById(errorOrder.getOrderId())
                            .orElseThrow(new BusinessException("订单"));
                    Asset asset = assetRepo.findById(order.getAssetId()).orElseThrow(new BusinessException("无"));
                    Collection collection = collectionRepo.findById(order.getCollectionId()).orElse(null);
                    if (AssetStatus.NORMAL == asset.getStatus()
                            && OrderStatus.CANCELLED == order.getStatus()
                            && collection != null) {
                        order.setStatus(OrderStatus.NOT_PAID);
                        order.setCreatedAt(LocalDateTime.now());
                        orderRepo.save(order);
                        rocketMQTemplate.syncSend("order-notify-topic",
                                new OrderNotifyEvent(errorOrder.getOrderId(), PayMethod.ALIPAY, errorOrder.getTransactionId(), System.currentTimeMillis()));
                    } else if (order.getStatus() == OrderStatus.FINISH) {
                        errorOrderRepo.delete(errorOrder);
                    } else {
                        JSONObject res = sandPayService.refund(order.getId() + "", order.getTotalPrice());
                        if ("000000".equals(res.getJSONObject("head").getString("respCode"))) {
                            errorOrderRepo.delete(errorOrder);
                        }
                    }
                });
    }

    @Test
    public void refunddd() {
        errorOrderRepo.findAll().stream().filter(o ->
                        "gift".equals(o.getType()) &&
                                o.getCreatedAt().isAfter(LocalDate.of(2022, 05, 13).atStartOfDay()))
                .forEach(errorOrder -> {
                    System.out.println(errorOrder.getOrderId());
                    String orderId = errorOrder.getOrderId() + "";
                    for (int i = orderId.length(); i < 12; i++) {
                        orderId = "0" + orderId;
                    }
                    JSONObject res = sandPayService.refund(orderId, new BigDecimal("1"));
                    if ("000000".equals(res.getJSONObject("head").getString("respCode"))) {
                        errorOrderRepo.delete(errorOrder);
                    }
                });
    }

    @Test
    public void test() {
        System.out.println(orderService.checkLimit(8161101L, 9850L));
    }


    @Test
    public void cancelRefundGas() throws ExecutionException, InterruptedException {
        new ForkJoinPool(500).submit(() -> {
            List<BalanceRecord> recordList = balanceRecordRepo.findByType(BalanceType.REFUND);
            recordList.parallelStream().forEach(r -> {
                userBalanceRepo.modifyBalance(r.getUserId(), new BigDecimal("-1"));
                balanceRecordRepo.delete(r);
            });
        }).get();
    }

    @Test
    public void refundGas() throws ExecutionException, InterruptedException {
        new ForkJoinPool(500).submit(() -> {
            List<Order> list = orderRepo.findByCollectionId(8657801L).stream()
                    .filter(o -> o.getStatus() == OrderStatus.FINISH || o.getStatus() == OrderStatus.PROCESSING)
                    .collect(Collectors.toList());
            list.parallelStream().forEach(o -> {
                userBalanceService.modifyBalance(o.getUserId(), new BigDecimal(1), BalanceType.REFUND, null, false, null);
            });
        }).get();
    }
}