package com.m2pool.lease.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.github.pagehelper.PageHelper;

import com.github.pagehelper.PageInfo;
import com.m2pool.common.redis.service.RedisService;
import com.m2pool.common.security.utils.SecurityUtils;
import com.m2pool.lease.redis.RedisCoinInfoKey;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.entity.*;
import com.m2pool.lease.mapper.*;
import com.m2pool.lease.service.LeaseUserOwnedProductService;
import com.m2pool.lease.vo.BaseVo;
import com.m2pool.lease.vo.UserOwnedProductVo;
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.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * <p>
 * 用户拥有商品详情表 服务实现类
 * </p>
 *
 * @author yyb
 * @since 2025-07-23
 */
@Service
public class LeaseUserOwnedProductServiceImpl extends ServiceImpl<LeaseUserOwnedProductMapper, LeaseUserOwnedProduct> implements LeaseUserOwnedProductService {

    @Resource
    private LeaseUserOwnedProductMapper leaseUserOwnedProductMapper;

    @Resource
    private LeaseProductMachineMapper leaseProductMachineMapper;

    @Resource
    private RedisService redisService;

    @Override
    public PageResult<UserOwnedProductDto> getOwnedList(UserOwnedProductVo userOwnedProductVo) {
        PageHelper.startPage(userOwnedProductVo.getPageNum(), userOwnedProductVo.getPageSize());
        //查询已购买的商品集合 按租约状态 未过期在前  + 结束时间 最先结束的在前排序
        List<LeaseUserOwnedProduct> leaseUserOwnedProducts = leaseUserOwnedProductMapper.selectList(new LambdaQueryWrapper<LeaseUserOwnedProduct>()
                .eq(LeaseUserOwnedProduct::getUserId, SecurityUtils.getUsername())
                .eq(LeaseUserOwnedProduct::getDel, false)
                .orderByAsc(LeaseUserOwnedProduct::getStatus)
                .orderByDesc(LeaseUserOwnedProduct::getEndTime));
        PageInfo<LeaseUserOwnedProduct> pageInfo = new PageInfo<>(leaseUserOwnedProducts);
        if (leaseUserOwnedProducts.isEmpty()){
            PageResult<UserOwnedProductDto> fail = PageResult.fail(null, "用户未购买商品");
            PageHelper.clearPage();
            return fail;
        }
        Map<String, List<UserMinerDto>> userAndMinerList = leaseUserOwnedProducts.stream().map(
                leaseUserOwnedProduct ->
                        UserMinerDto.builder()
                                .user(leaseUserOwnedProduct.getUser())
                                .miner(leaseUserOwnedProduct.getMiner())
                                .coin(leaseUserOwnedProduct.getCoin())
                                .build()
        ).collect(Collectors.groupingBy(UserMinerDto::getCoin));
        List<UserMinerPowerDto> userMinerPowerList = new ArrayList<>();
        userAndMinerList.forEach((coin, userMinerDtos) -> {
            userMinerPowerList.addAll( leaseUserOwnedProductMapper.getUserMinerPower(userMinerDtos, coin));
        });

        //根据user+miner+coin 获取到实时的算力
        Map<String, UserMinerPowerDto> collect = userMinerPowerList.stream()
                .collect(Collectors.toMap(
                        dto -> dto.getUser() + "-" + dto.getMiner() + "-" + dto.getCoin(),
                        dto -> dto
                ));

        //获取币价
        Map<String, BigDecimal> coinPrice = new HashMap<>();
        //封装返回对象
        List<UserOwnedProductDto> userOwnedProducts = leaseUserOwnedProducts.stream().map(leaseUserOwnedProduct ->{
            String coin = leaseUserOwnedProduct.getCoin();
            BigDecimal bigDecimal = coinPrice.putIfAbsent(coin, redisService.getCacheBigDecimal(RedisCoinInfoKey.getPiceKey(coin)));

            UserOwnedProductDto build = UserOwnedProductDto.builder()
                    .id(leaseUserOwnedProduct.getId())
                    .userId(leaseUserOwnedProduct.getUserId())
                    .productMachineId(leaseUserOwnedProduct.getProductMachineId())
                    .orderItemId(leaseUserOwnedProduct.getOrderItemId())
                    .startTime(leaseUserOwnedProduct.getStartTime())
                    .productMachineId(leaseUserOwnedProduct.getProductMachineId())
                    .endTime(leaseUserOwnedProduct.getEndTime())
                    .currentIncome(leaseUserOwnedProduct.getCurrentIncome())
                    .estimatedEndIncome(leaseUserOwnedProduct.getEstimatedEndIncome())
                    .currentUsdtIncome(bigDecimal == null ? leaseUserOwnedProduct.getCurrentUsdtIncome() : bigDecimal.multiply(leaseUserOwnedProduct.getCurrentIncome()))
                    .estimatedEndUsdtIncome(leaseUserOwnedProduct.getEstimatedEndUsdtIncome())
                    .purchasedComputingPower(leaseUserOwnedProduct.getPurchasedComputingPower())
                    .status(leaseUserOwnedProduct.getStatus())
                    .type(leaseUserOwnedProduct.getType())
                    .createTime(leaseUserOwnedProduct.getCreateTime())
                    .build();
            UserMinerPowerDto userMinerPowerDto = collect.get(leaseUserOwnedProduct.getUser() + "-" + leaseUserOwnedProduct.getMiner() + "-"+ leaseUserOwnedProduct.getCoin());
            if (userMinerPowerDto != null){
                //已购机器30分算力
                build.setCurrentComputingPower(userMinerPowerDto.getPower());
            }
            return build;
        }).collect(Collectors.toList());
        PageResult<UserOwnedProductDto> success = PageResult.success(userOwnedProducts);
        success.setTotal(pageInfo.getTotal());
        success.setTotalPage(pageInfo.getPages());
        PageHelper.clearPage();
        return success;
    }


    @Override
    public Result<UserOwnedProductDto> getOwnedById(BaseVo baseVo) {
        LeaseUserOwnedProduct leaseUserOwnedProduct = leaseUserOwnedProductMapper.selectById(baseVo.getId());
        List<LeaseProductMachine> leaseProductMachines = new ArrayList<>();
        leaseProductMachines.add(LeaseProductMachine.builder()
                        .user(leaseUserOwnedProduct.getUser())
                        .miner(leaseUserOwnedProduct.getMiner())
                .build());
        BigDecimal price = redisService.getCacheBigDecimal(RedisCoinInfoKey.getPiceKey(leaseUserOwnedProduct.getCoin()));
        //获取实时算力
        List<ProductMachineDto> recentlyFiveMinutesData = leaseProductMachineMapper.getRecentlyFiveMinutesData(leaseProductMachines, leaseUserOwnedProduct.getCoin());
        Integer status = leaseUserOwnedProduct.getStatus();
        BigDecimal currentIncome = status == 0 ? leaseUserOwnedProduct.getSettleIncome() : leaseUserOwnedProduct.getCurrentIncome();
        BigDecimal currentUsdtIncome = currentIncome.multiply(price);
        UserOwnedProductDto build = UserOwnedProductDto.builder()
                .id(leaseUserOwnedProduct.getId())
                .userId(leaseUserOwnedProduct.getUserId())
                .productMachineId(leaseUserOwnedProduct.getProductMachineId())
                .orderItemId(leaseUserOwnedProduct.getOrderItemId())
                .startTime(leaseUserOwnedProduct.getStartTime())
                .productMachineId(leaseUserOwnedProduct.getProductMachineId())
                .endTime(leaseUserOwnedProduct.getEndTime())
                .estimatedEndIncome(leaseUserOwnedProduct.getEstimatedEndIncome())
                .estimatedEndUsdtIncome(leaseUserOwnedProduct.getEstimatedEndUsdtIncome())
                .purchasedComputingPower(leaseUserOwnedProduct.getPurchasedComputingPower())
                .currentIncome(currentIncome)
                .currentUsdtIncome(currentUsdtIncome)
                .status(status)
                .type(leaseUserOwnedProduct.getType())
                .createTime(leaseUserOwnedProduct.getCreateTime())
                .build();
        if (!recentlyFiveMinutesData.isEmpty()){
            build.setCurrentComputingPower(recentlyFiveMinutesData.get(0).getComputingPower().divide(BigDecimal.valueOf(24 * 60 * 60), 2, RoundingMode.HALF_UP));
        }
        return Result.success(build);
    }

    /**
     * 支付验证成功后去修改订单等信息(迁移到这里让事务生效)
     * @param leaseOrderItems
     * @return 支付订单验证成功的个数
     */
    @Transactional
    @Override
    public boolean afterPaySuccessTodoSomeEvent(List<LeaseOrderItem> leaseOrderItems){
        //回调才需要
        // 修改商品售出状态
        //List<Long> ids = leaseOrderItems.stream().map(LeaseOrderItem::getProductMachineId).collect(Collectors.toList());
        //int update = leaseProductMachineMapper.update(LeaseProductMachine.builder().saleState(1).build(),
        //        new LambdaQueryWrapper<LeaseProductMachine>().eq(LeaseProductMachine::getDel, false).in(LeaseProductMachine::getId, ids));
        // 添加购买记录
        //List<LeaseOrderItem> leaseOrderItems2 = leaseOrderItemMapper.selectList(new LambdaQueryWrapper<LeaseOrderItem>()
        //        .in(LeaseOrderItem::getProductMachineId, ids));

        //获取卖方收款币种币价
        BigDecimal price = redisService.getCacheBigDecimal(RedisCoinInfoKey.getPiceKey(leaseOrderItems.get(0).getCoin()));
        List<LeaseUserOwnedProduct> collect = leaseOrderItems.stream()
                .map(item -> {
                    // 获取当前的 LocalDateTime
                    LocalDateTime now = LocalDateTime.now();
                    // 获取当天 0 点的 LocalDateTime
                    LocalDateTime startOfDay = now.toLocalDate().atStartOfDay().plusDays(1);
                    return LeaseUserOwnedProduct.builder()
                            .miner(item.getMiner())
                            .userId(SecurityUtils.getUsername())
                            .user(item.getUser())
                            .address(item.getAddress())
                            .productMachineId(item.getProductMachineId())
                            .orderItemId(item.getId())
                            .orderId(item.getOrderId())
                            //预估收益由订单创建时固定  实际收益通过定时任务实时计算
                            .estimatedEndIncome(item.getTheoryIncome())
                            .estimatedEndUsdtIncome(price == null ? BigDecimal.ZERO : item.getTheoryIncome().multiply(price))
                            .coin(item.getCoin())
                            .startTime(startOfDay)
                            .type(item.getType() ? 1 : 0)
                            .endTime(startOfDay.plusDays(item.getLeaseTime()))
                            .build();
                }).collect(Collectors.toList());
        boolean b1 = saveBatch(collect);

        return b1;
    }
}
