package com.m2pool.lease.service.impl;

import cn.hutool.json.JSONUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.m2pool.lease.constant.PaymentStatus;
import com.m2pool.lease.dto.PaymentCallbackDto;
import com.m2pool.lease.dto.PaymentRecordDto;
import com.m2pool.lease.mq.message.RabbitmqPoolProxyMessage;
import com.m2pool.lease.dto.Result;
import com.m2pool.lease.entity.LeaseOrderInfo;
import com.m2pool.lease.entity.LeaseOrderItem;
import com.m2pool.lease.entity.LeasePaymentRecord;
import com.m2pool.lease.exception.PaymentException;
import com.m2pool.lease.mapper.LeaseOrderInfoMapper;
import com.m2pool.lease.mapper.LeaseOrderItemMapper;
import com.m2pool.lease.mapper.LeasePaymentRecordMapper;
import com.m2pool.lease.service.LeasePaymentRecordService;
import com.m2pool.lease.service.LeaseUserOwnedProductService;
import com.m2pool.lease.utils.HttpPayUtils;
import com.m2pool.lease.vo.CheckPayStatusVo;
import com.m2pool.lease.vo.OrderVo;
import com.m2pool.lease.vo.PayVo;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.time.ZoneId;
import java.util.*;
import java.util.stream.Collectors;

import static com.m2pool.lease.constant.OrderStatus.FULLY_PAID;
import static com.m2pool.lease.constant.OrderStatus.PARTIALLY_PAID;
import static com.m2pool.lease.constant.PaymentStatus.*;
import static com.m2pool.lease.constant.RabbitmqConstant.POOL_PROXY_QUEUE_NAME;
import static com.m2pool.lease.utils.HttpPayUtils.PAY_ETH;


/**
 * <p>
 * 支付记录表 服务实现类
 * </p>
 *
 * @author yyb
 * @since 2025-07-23
 */
@Service
public class LeasePaymentRecordServiceImpl extends ServiceImpl<LeasePaymentRecordMapper, LeasePaymentRecord> implements LeasePaymentRecordService {



    @Resource
    private RabbitTemplate rabbitTemplate;

    @Resource
    private LeaseOrderItemMapper leaseOrderItemMapper;

    @Resource
    private LeasePaymentRecordMapper leasePaymentRecordMapper;

    @Resource
    private ThreadPoolTaskExecutor customThreadPool;

    @Resource
    private LeaseOrderInfoMapper leaseOrderInfoMapper;

    @Resource
    private LeaseUserOwnedProductService leaseUserOwnedProductService;

    @Override
    @Transactional
    public Result<List<PaymentRecordDto>> addPayOrder(OrderVo orderVo) {
        //1.根据订单id查询订单详情信息
        List<LeaseOrderItem> leaseOrderItems = leaseOrderItemMapper.selectList(new LambdaQueryWrapper<LeaseOrderItem>()
                .eq(LeaseOrderItem::getOrderId, orderVo.getOrderId()));

        //2.按商品ID分组，并生成支付订单列表
        Map<Long, List<LeaseOrderItem>> productItemsMap = leaseOrderItems.stream()
                .collect(Collectors.groupingBy(LeaseOrderItem::getProductId));
        //3.生成支付订单列表 + 封装返回对象
        List<PaymentRecordDto> paymentRecordDTOs = new ArrayList<>();

        List<LeasePaymentRecord> paymentRecords = productItemsMap.values().stream()
                .map(items -> {
                    LeaseOrderItem firstItem = items.get(0);
                    BigDecimal totalAmount = items.stream()
                            .map(LeaseOrderItem::getPrice)
                            .reduce(BigDecimal.ZERO, BigDecimal::add);
                    Long orderId = orderVo.getOrderId();
                    Long productId = firstItem.getProductId();
                    String payCoin = firstItem.getPayCoin();
                    String address = firstItem.getAddress();
                    paymentRecordDTOs.add(PaymentRecordDto.builder()
                            .payCoin(payCoin)
                            .amount(totalAmount)
                            .payAddress(address)
                            .build());

                    return LeasePaymentRecord.builder()
                            .orderId(orderId)
                            .productId(productId)
                            .payCoin(payCoin)
                            .amount(totalAmount)
                            .payAddress(address)
                            .build();
                })
                .collect(Collectors.toList());

        //4.保存支付订单
        boolean saved = saveBatch(paymentRecords);
        if (saved) {
            return Result.success(paymentRecordDTOs);
        } else {
            return Result.fail("生成支付订单失败");
        }
    }

    @Override
    public Result<List<PaymentRecordDto>> getPayOrderByOrderId(OrderVo orderVo) {
        List<LeasePaymentRecord> leasePaymentRecords = leasePaymentRecordMapper.selectList(new LambdaQueryWrapper<LeasePaymentRecord>()
                .eq(LeasePaymentRecord::getOrderId, orderVo.getOrderId())
                .eq(LeasePaymentRecord::getDel, false));
        List<PaymentRecordDto> collect = leasePaymentRecords.stream()
                .map(record -> PaymentRecordDto.builder()
                        .id(record.getId())
                        .payCoin(record.getPayCoin())
                        .amount(record.getAmount())
                        .payAddress(record.getPayAddress())
                        .status(record.getStatus())
                        .img(record.getQrcode())
                        .build()).collect(Collectors.toList());
        return Result.success(collect);
    }


    @Override
    @Transactional
    public Result<List<PaymentCallbackDto>> paymentCallbackBatch(List<CheckPayStatusVo> checkPayStatusVoList) {
        List<PaymentCallbackDto> paymentCallbackDTOs = new ArrayList<>();
        //1.查询处于待支付中状态（2）的订单
        List<Long> payIds = checkPayStatusVoList.stream().map(CheckPayStatusVo::getId).collect(Collectors.toList());
        List<LeasePaymentRecord> leasePaymentRecords = leasePaymentRecordMapper.selectList(new LambdaQueryWrapper<LeasePaymentRecord>()
                .in(LeasePaymentRecord::getId, payIds)
                .eq(LeasePaymentRecord::getDel, true)
                .nested(wrapper -> wrapper
                        .eq(LeasePaymentRecord::getStatus, 2)
                        .or()
                        .eq(LeasePaymentRecord::getStatus, 10)));

        List<Long> orderIds = leasePaymentRecords.stream().map(LeasePaymentRecord::getOrderId).collect(Collectors.toList());
        //2.根据订单id查询订单详情信息
        List<LeaseOrderItem> leaseOrderItems = leaseOrderItemMapper.selectList(new LambdaQueryWrapper<LeaseOrderItem>()
                .in(LeaseOrderItem::getOrderId, orderIds));
        //3.按商店id分组
        Map<Long, List<LeaseOrderItem>> productItemsMap = leaseOrderItems.stream()
                .collect(Collectors.groupingBy(LeaseOrderItem::getShopId));

        //记录是否所有都支付成功
        int isAll = 0;
        //4.按店铺分组---->合并店铺下所有支付订单----> 按所有总交易金额 去填充这些订单---->填充慢则表示这一笔订单支付成功----> 发货
        for (LeasePaymentRecord record : leasePaymentRecords) {
            //4.1 调用三方api校验支付是否成功
            PaymentCallbackDto paymentCallbackDto = paymentCallback(record);

            if (paymentCallbackDto.getIsPayAll() == 1){
                //4.2 修改商品售出状态 + 新增机器到已购表中  (为了保证成功需要通过消息中间件达成最终一致性 demo暂时不修改)
                List<LeaseOrderItem> leaseOrderItemList = productItemsMap.get(record.getShopId());
                boolean isSuccess = leaseUserOwnedProductService.afterPaySuccessTodoSomeEvent(leaseOrderItemList);
                if (!isSuccess){
                    return Result.fail("支付校验成功√-->货款已付清√-->发货失败×。请提交工单发送订单给客服或者通过聊天系统联系客服解决");
                }
                record.setStatus(1);
                int i = leasePaymentRecordMapper.updateById(record);
                isAll += i;
                //4.3 发送rabbitmq消息给矿池代理
                sendRabbitmqMessage(leaseOrderItemList);
            }else if (paymentCallbackDto.getIsPayAll() == 10){
                //支付了部分货款改状态---但是不发货
                leasePaymentRecordMapper.updateById(LeasePaymentRecord.builder().id(record.getId()).status(10).build());
            }
            paymentCallbackDto.setTotalAmount(record.getAmount());
            paymentCallbackDTOs.add(paymentCallbackDto);
        }
        //5.修改订单状态为 1全部已支付  10部分已支付
        int status = isAll == leasePaymentRecords.size() ? 1 : 10;
        Long orderId = leasePaymentRecords.get(0).getOrderId();
        int i = leaseOrderInfoMapper.updateById(LeaseOrderInfo.builder().id(orderId).status(status).build());
        if (i > 0){
            return Result.success(paymentCallbackDTOs);
        }else {
            return Result.fail("校验失败");
        }
    }


    @Override
    @Transactional
    public Result<PaymentCallbackDto> paymentCallbackByPayId(CheckPayStatusVo baseVo) {
        LeasePaymentRecord record = leasePaymentRecordMapper.selectById(baseVo.getId());
        record.setFrom(baseVo.getForm());
        record.setHash(baseVo.getHash());
        //支付状态为2 待支付 或者 10 支付成功--已支付部分货款 两种状态可校验
        if (record.getStatus() == 10 || record.getStatus() == 2){
            //1.根据订单id + 店铺id 查询订单详情信息 （支付订单按shop分的，不再按商品分）
            List<LeaseOrderItem> leaseOrderItems = leaseOrderItemMapper.selectList(new LambdaQueryWrapper<LeaseOrderItem>()
                    .eq(LeaseOrderItem::getOrderId, record.getOrderId()).eq(LeaseOrderItem::getShopId, record.getShopId()));

            //2.调用三方api校验支付是否成功
            PaymentCallbackDto paymentCallbackDto = paymentCallback(record);
            if (paymentCallbackDto.getIsPayAll() == 1){
                boolean isSuccess = leaseUserOwnedProductService.afterPaySuccessTodoSomeEvent(leaseOrderItems);
                if (!isSuccess){
                    return Result.fail("支付校验成功√-->货款已付清√-->发货失败×。请提交工单发送订单给客服或者通过聊天系统联系客服解决");
                }
                record.setStatus(1);
                leasePaymentRecordMapper.updateById(record);
                //2.1 发送rabbitmq消息给矿池代理
                sendRabbitmqMessage(leaseOrderItems);
            } else if (paymentCallbackDto.getIsPayAll() == 10){
                //2.2 支付了部分货款改状态---但是不发货
                leasePaymentRecordMapper.updateById(LeasePaymentRecord.builder().id(record.getId()).status(10).build());
            }
            //3.查询订单是否下所有支付订单都已支付完成
            Long l = leasePaymentRecordMapper.selectCount(new LambdaQueryWrapper<LeasePaymentRecord>()
                    .eq(LeasePaymentRecord::getOrderId, record.getOrderId())
                    .eq(LeasePaymentRecord::getDel, true)
                    .ne(LeasePaymentRecord::getStatus,1));
            //4.修改订单为全部已支付
            if (l == 0){
                leaseOrderInfoMapper.updateById(LeaseOrderInfo.builder().id(record.getOrderId()).status(1).build());
            }
            return Result.success(paymentCallbackDto);
        }
        return Result.fail("验证失败,该订单状态不为支付成功未验证状态");
    }

    @Override
    @Transactional
    public void paymentCallbackTask(List<LeasePaymentRecord> leasePaymentRecordList) {
        List<Long> orderIds = leasePaymentRecordList.stream().map(LeasePaymentRecord::getOrderId).distinct().collect(Collectors.toList());
        //1---根据订单id查询订单详情信息
        List<LeaseOrderItem> leaseOrderItems = leaseOrderItemMapper.selectList(new LambdaQueryWrapper<LeaseOrderItem>()
                .in(LeaseOrderItem::getOrderId, orderIds));
        //2---按商店id - 订单id 分组
        Map<String, List<LeaseOrderItem>> productItemsMap = leaseOrderItems.stream()
                .collect(Collectors.groupingBy(
                        item -> item.getShopId() + "-" + item.getOrderId()
                ));
        //3---支付订单按支付地址分组 校验
        Map<String, List<LeasePaymentRecord>> shopMaps = leasePaymentRecordList.stream().collect(Collectors.groupingBy(LeasePaymentRecord::getPayAddress));

        List<LeasePaymentRecord> afterCheckPaymentList = shopMaps.entrySet().stream()
                .map(entry -> {
                    String key = entry.getKey();
                    List<LeasePaymentRecord> values = entry.getValue();
                    // 查找已经支付的金额
                    BigDecimal paySuccessAmount = values.stream().map(LeasePaymentRecord::getPayAmount).reduce(BigDecimal.ZERO, BigDecimal::add);
                    BigDecimal alreadyPayAmount = getAlreadyPayAmount(key, values).subtract(paySuccessAmount);

                    // 在迭代过程中修改列表，使用 fori 循环避免 ConcurrentModificationException
                    for (int i = 0; i < values.size(); i++) {
                        LeasePaymentRecord leasePaymentRecord = values.get(i);
                        BigDecimal needPayAmount = leasePaymentRecord.getAmount();
                        BigDecimal payAmount = leasePaymentRecord.getPayAmount();
                        // 如果该支付订单已支付了部分金额 剩下需支付需减去该值
                        if (payAmount.compareTo(BigDecimal.ZERO) != 0) {
                            needPayAmount = needPayAmount.subtract(payAmount);
                        }
                        // 已支付金额 不等于 需支付总金额
                        if (payAmount.compareTo(needPayAmount) != 0) {
                            if (needPayAmount.compareTo(alreadyPayAmount) < 0) {
                                // 条件1: 交易记录金额大于需要支付的金额------> 该订单状态可改为 1全部已支付
                                alreadyPayAmount = alreadyPayAmount.subtract(needPayAmount);
                                leasePaymentRecord.setStatus(PAYMENT_SUCCESS_FULL.getCode());
                                leasePaymentRecord.setPayAmount(leasePaymentRecord.getAmount());
                            } else if (needPayAmount.compareTo(alreadyPayAmount) > 0 && alreadyPayAmount.compareTo(BigDecimal.ZERO) != 0) {
                                // 条件2: 交易记录金额小于需要支付的金额 ,但是交易记录金额不为0 ------>  该订单可改为状态 10部分已支付
                                alreadyPayAmount = BigDecimal.ZERO;
                                leasePaymentRecord.setStatus(PAYMENT_SUCCESS_PARTIAL.getCode());
                                leasePaymentRecord.setPayAmount(alreadyPayAmount);
                            } else if (PAYMENT_SUCCESS_PARTIAL.getCode() == leasePaymentRecord.getStatus()) {
                                // 条件3: 走到这里说明,交易金额已经分配完毕。 如果本身为部分已支付,直接去除
                                values.remove(i);
                                i--;
                            }
                        } else {
                            // 已支付金额 等于 需支付总金额 直接剔除
                            values.remove(i);
                            i--;
                        }
                    }
                    return values;
                })
                .flatMap(List::stream) // 展开嵌套的列表
                .collect(Collectors.toList());


        List<LeaseOrderItem> rabbitmqMessages = new ArrayList<>();
        //4---更新支付状态变化的支付订单 + 支付订单为完成支付的 订单开始 发货
        for (LeasePaymentRecord record : afterCheckPaymentList) {
            //4.1全部支付成功的才能发货
            if (PaymentStatus.PAYMENT_SUCCESS_FULL.getCode() == record.getStatus()){
                String key = record.getShopId() + "-" + record.getOrderId();
                List<LeaseOrderItem> leaseOrderItemList  = productItemsMap.get(key);
                leaseUserOwnedProductService.afterPaySuccessTodoSomeEvent(leaseOrderItemList);
                rabbitmqMessages.addAll(leaseOrderItemList);
            }
            //4.2 修改支付订单的状态
            leasePaymentRecordMapper.updateById(record);
        }



        //5---发送rabbitmq消息给矿池代理
        sendRabbitmqMessage(rabbitmqMessages);

        //6---修改普通订单状态
        //统计每个普通订单对应的支付订单数量
        Map<Long, Long> orderIdCountMap = leasePaymentRecordList.stream()
                .collect(Collectors.groupingBy(LeasePaymentRecord::getOrderId, Collectors.counting()));
        // 统计每个订单对应的支付已全部完成的数量
        Map<Long, Long> fullPaidCountMap = leasePaymentRecordList.stream()
                .filter(record -> record.getStatus() == PAYMENT_SUCCESS_FULL.getCode())
                .collect(Collectors.groupingBy(LeasePaymentRecord::getOrderId, Collectors.counting()));
        // 统计每个订单对应的部分已完成的数量
        Map<Long, Long> partialPaidCountMap = leasePaymentRecordList.stream()
                .filter(record -> record.getStatus() == PAYMENT_SUCCESS_PARTIAL.getCode())
                .collect(Collectors.groupingBy(LeasePaymentRecord::getOrderId, Collectors.counting()));

        // 遍历 orderIdCountMap，更新订单状态
        for (Map.Entry<Long, Long> entry : orderIdCountMap.entrySet()) {
            Long orderId = entry.getKey();
            Long totalCount = entry.getValue();
            Long fullPaidCount = fullPaidCountMap.getOrDefault(orderId, 0L);
            Long partialPaidCount = partialPaidCountMap.getOrDefault(orderId, 0L);
            if (Objects.equals(fullPaidCount, totalCount)) {
                // 全部已完成
                leaseOrderInfoMapper.updateById(LeaseOrderInfo.builder().id(orderId).status(FULLY_PAID.getCode()).build());
                //TODO 长连接联系前端支付已完成
            } else if (partialPaidCount > 0) {
                // 部分已完成
                leaseOrderInfoMapper.updateById(LeaseOrderInfo.builder().id(orderId).status(PARTIALLY_PAID.getCode()).build());
            }
        }



    }


    /**
     * 获取当前用户已支付的金额
     * @param leasePaymentRecordList
     * @return
     */
    private BigDecimal getAlreadyPayAmount(String payAddress,List<LeasePaymentRecord> leasePaymentRecordList) {
        LeasePaymentRecord leasePaymentRecord = leasePaymentRecordList.get(0);
        PayVo build = PayVo.builder()
                .ts(leasePaymentRecord.getCreateTime().atZone(ZoneId.systemDefault()).toInstant().getEpochSecond())
                .address(payAddress)
                .build();
        HttpPayUtils.PaymentDto paymentDto = HttpPayUtils.doPost(PAY_ETH, JSONUtil.toJsonStr(build));

        BigDecimal totalAmount = BigDecimal.ZERO;
        List<HttpPayUtils.PaymentData> paymentData = handlerResponse(paymentDto);
        for (HttpPayUtils.PaymentData result : paymentData){
            String valueStr = result.getValue();
            BigDecimal divisor = BigDecimal.TEN.pow(6);
            BigDecimal resultAmount = new BigDecimal(valueStr).divide(divisor,6, RoundingMode.HALF_UP);
            totalAmount = totalAmount.add(resultAmount);
        }

        return totalAmount;
    }


    /**
     * 调用三方api 进行支付校验
     * @param record
     * @return
     */
    private PaymentCallbackDto paymentCallback(LeasePaymentRecord record) {
        PayVo build = PayVo.builder()
                .ts(record.getCreateTime().atZone(ZoneId.systemDefault()).toInstant().getEpochSecond())
                .coin(record.getPayCoin())
                .amount(record.getAmount())
                .address(record.getPayAddress())
                .build();
        HttpPayUtils.PaymentDto paymentDto = HttpPayUtils.doPost(PAY_ETH, JSONUtil.toJsonStr(build));

        List<HttpPayUtils.PaymentData> paymentData = handlerResponse(paymentDto);
        if  (paymentData != null && !paymentData.isEmpty()){
            return payIsSuccess(record, paymentData);
        }else{
            throw new PaymentException("验证失败,卖方不存在转账记录");
        }
    }

    /**
     * 校验代码
     * @param record
     * @param paymentData
     * @return
     */
    private PaymentCallbackDto payIsSuccess(LeasePaymentRecord record,List<HttpPayUtils.PaymentData> paymentData){
        //待支付状态为2
        int isPayAll = 2;
        BigDecimal noPayAmount = record.getAmount();
        for (HttpPayUtils.PaymentData result : paymentData){
            String valueStr = result.getValue();
            BigDecimal divisor = BigDecimal.TEN.pow(6);
            BigDecimal resultAmount = new BigDecimal(valueStr).divide(divisor,6, RoundingMode.HALF_UP);
            long timeStamp = Long.parseLong(result.getTimeStamp());
            long ts = record.getCreateTime().atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
            //交易hash 和 买家钱包地址 有一个校验通过即可(只适用于自营校验)
            if (timeStamp >= ts && (result.getFrom().equals(record.getFrom()) || result.getHash().equals(record.getHash()))){
                noPayAmount = noPayAmount.subtract(resultAmount);
                //全部货款已支付
                if (noPayAmount.compareTo(BigDecimal.ZERO) == 0){
                    isPayAll = 1;
                    break;
                }
            }


        }
        //已支付部分货款
        if (noPayAmount.compareTo(record.getAmount()) != 0 && noPayAmount.compareTo(BigDecimal.ZERO) != 0){
            isPayAll = 10;
        }

        return PaymentCallbackDto.builder().isPayAll(isPayAll).noPayAmount(noPayAmount).build();
    }

    /**
     * 三方api调用异常
     * @param paymentDto
     * @return
     */
   private List<HttpPayUtils.PaymentData> handlerResponse(HttpPayUtils.PaymentDto paymentDto){
       if (paymentDto != null){
           if (paymentDto.isResult() && paymentDto.getCode() == 0) {
               // 支付成功，处理返回的交易数据
               List<HttpPayUtils.PaymentData> transactions = paymentDto.getData();
               return transactions;
           } else {
               // 支付失败，根据 code 处理不同错误
               switch (paymentDto.getCode()) {
                   case -1:
                       throw new PaymentException("未转账");
                   case -2:
                       throw new PaymentException("coin参数不支持");
                   default:
                       throw new PaymentException("支付未知错误");
               }
           }
       }else {
           return null;
       }

    }

    /**
     * 发送rabbitmq消息给矿机代理
     * @param leaseOrderItems
     */
    public void sendRabbitmqMessage( List<LeaseOrderItem> leaseOrderItems) {
        leaseOrderItems.forEach(item -> {
            customThreadPool.execute(()->{
                RabbitmqPoolProxyMessage rabbitmqPoolProxyMessage = RabbitmqPoolProxyMessage.builder()
                        .MethodID(0)
                        .Msg("")
                        .ID(item.getUser() + "-" + item.getMiner())
                        .Address(item.getAddress())
                        .build();
                try {
                    rabbitTemplate.convertAndSend(POOL_PROXY_QUEUE_NAME, rabbitmqPoolProxyMessage);
                } catch (Exception e) {
                    System.err.println("发送失败: " + e.getMessage());
                }
            });
        });

    }








}
