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.core.utils.StringUtils;
import com.m2pool.common.security.utils.SecurityUtils;
import com.m2pool.lease.dto.*;
import com.m2pool.lease.dto.v2.*;
import com.m2pool.lease.entity.LeaseMachine;
import com.m2pool.lease.entity.LeaseMachineConfig;
import com.m2pool.lease.entity.LeaseMachinePrice;
import com.m2pool.lease.entity.LeaseShop;
import com.m2pool.lease.exception.MachineException;
import com.m2pool.lease.mapper.*;
import com.m2pool.lease.service.LeaseMachineConfigService;
import com.m2pool.lease.service.LeaseMachinePriceService;
import com.m2pool.lease.service.LeaseMachineService;
import com.m2pool.lease.utils.UuidGeneratorUtil;
import com.m2pool.lease.vo.BaseVo;
import com.m2pool.lease.vo.ProductPageVo;
import com.m2pool.lease.vo.v2.*;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <p>
 * gpu类型出售矿机表 服务实现类
 * </p>
 *
 * @author yyb
 * @since 2025-11-21
 */
@Service
public class LeaseMachineServiceImpl extends ServiceImpl<LeaseMachineMapper, LeaseMachine> implements LeaseMachineService {


    @Resource
    private LeaseShopConfigMapper leaseShopConfigMapper;

    @Resource
    private LeaseMachineMapper leaseMachineMapper;

    @Resource
    private LeaseShopMapper leaseShopMapper;

    @Resource
    private LeaseMachineConfigMapper leaseMachineConfigMapper;

    @Resource
    private LeaseMachinePriceMapper leaseMachinePriceMapper;

    @Resource
    private LeaseMachineConfigService leaseMachineConfigService;

    @Resource
    private LeaseMachinePriceService leaseMachinePriceService;

    public LeaseShop getShopById() {
        return leaseShopMapper.selectOne(new LambdaQueryWrapper<LeaseShop>().eq(LeaseShop::getUserEmail, SecurityUtils.getUsername())
                .eq(LeaseShop::getDel, false));
    }
    @Override
    public PageResult<ShopInfoDto> getShopList(ProductPageVo productPageVo) {
        //获取到矿机
        Set<Long> shopIds = leaseMachineMapper.getShopIds();
        if (shopIds.isEmpty()){
            //店铺不存在商品
            return PageResult.success(new ArrayList<>());
        }
        PageHelper.startPage(productPageVo.getPageNum(), productPageVo.getPageSize());
        List<ShopInfoDto> existsMachineShop = leaseMachineMapper.getExistsMachineShop(shopIds, productPageVo.getCoin(), productPageVo.getAlgorithm());
        PageInfo<ShopInfoDto> pageInfo = new PageInfo<>(existsMachineShop);
        //店铺支付方式
        List<PayTypeDto> payType = leaseShopConfigMapper.getPayType(new ArrayList<>(shopIds));
        Map<Long, List<PayTypeDto>> payTypeMap = payType.stream().collect(Collectors.groupingBy(PayTypeDto::getShopId));

        PageResult<ShopInfoDto> success = PageResult.success(existsMachineShop);
        for (ShopInfoDto shopInfoDto : success.getRows()) {
            shopInfoDto.setPayTypes(payTypeMap.get(shopInfoDto.getShopId()));
        }
        success.setTotal(pageInfo.getTotal());
        success.setTotalPage(pageInfo.getPages());
        PageHelper.clearPage();
        return success;
    }

    @Override
    public PageResult<MachineInfoDto> getShopMachineList(ShopMachineVo shopMachineVo) {
        //获取店铺钱包信息
        List<PayConfigDto> shopWalletInfo = leaseShopMapper.getShopWalletInfo(shopMachineVo.getShopId());
        //分页查询矿机基础信息
        PageHelper.startPage(shopMachineVo.getPageNum(), shopMachineVo.getPageSize());
        shopMachineVo =  buildQuery(shopMachineVo,shopWalletInfo.get(0));
        List<MachineInfoDto> machineInfoDtoList = leaseMachineMapper.getShopMachineList(shopMachineVo);
        PageInfo<MachineInfoDto> pageInfo = new PageInfo<>(machineInfoDtoList);
        //获取gpu和asic对应币种算力和月收益信息
        PageResult<MachineInfoDto> success = setGpuAndAsicInfo(PageResult.successColumns(machineInfoDtoList),shopMachineVo);
        success.setTotal(pageInfo.getTotal());
        success.setTotalPage(pageInfo.getPages());
        PageHelper.clearPage();
        return success;
    }

    /**
     * 设置gpu和asic 对应的收益列表信息
     * @param
     */
    public  PageResult<MachineInfoDto> setGpuAndAsicInfo(PageResult<MachineInfoDto> success,ShopMachineVo shopMachineVo) {
        List<MachineInfoDto> machineInfoDtoList = success.getRows();
        List<TableHeadersDto> columns = success.getColumns();
        if (!machineInfoDtoList.isEmpty()){
            List<Long> machineIds = machineInfoDtoList.stream()
                    .map(MachineInfoDto::getId).collect(Collectors.toList());
            //获取价格列表(价格列表只与主表有关，与machine_config 表无关)
            List<MachinePayTypeDto> machinePriceByMachineIds = leaseMachinePriceMapper.getMachinePriceByMachineIds(machineIds);
            Map<Long, List<MachinePayTypeDto>> machinePriceMap = machinePriceByMachineIds.stream()
                    .collect(Collectors.groupingBy(MachinePayTypeDto::getProductMachineId));

            //动态列：获取每个矿机前十个币种算法的配置
            List<PowerIncomeInfoDto> gpuConfigList = leaseMachineMapper.getGpuConfigList(machineIds);
            Map<Long, List<PowerIncomeInfoDto>> collect = gpuConfigList.stream()
                    .collect(Collectors.groupingBy(PowerIncomeInfoDto::getMachineId));
            for (MachineInfoDto machineInfo : machineInfoDtoList) {
                machineInfo.setPriceList(machinePriceMap.get(machineInfo.getId()));
                List<PowerIncomeInfoDto> powerIncomeInfoDtoList = collect.get(machineInfo.getId());
                for (int i = 0; i < powerIncomeInfoDtoList.size(); i++) {
                    PowerIncomeInfoDto powerIncomeInfoDto = powerIncomeInfoDtoList.get(i);
                    setDynamicColumn(columns,powerIncomeInfoDto,machineInfo);
                }
            }
            //排序分页后对象
            List<MachineInfoDto> sorted = sorted(machineInfoDtoList, shopMachineVo);
            success.setRows(sorted);
            success.setColumns(columns);

        }
        return success;
    }

    /**
     * 设置算力动态列
     * @param columns
     */
    public void setDynamicColumn(List<TableHeadersDto> columns,PowerIncomeInfoDto powerIncomeInfoDto,MachineInfoDto machineInfo){
        TableHeadersDto column = TableHeadersDto.builder()
                .label(powerIncomeInfoDto.getCoin())
                .type("hashrate")
                .unit(powerIncomeInfoDto.getUnit())
                .icon(powerIncomeInfoDto.getIcon())
                .width(100).build();
        int index = 1;

        for (TableHeadersDto tableHeadersDto : columns) {
            if (index < 10 && "hashrate".equals(tableHeadersDto.getType())){
                if (column.getLabel().equals(tableHeadersDto.getLabel())){
                    setDynamicPower(index,machineInfo,powerIncomeInfoDto);
                    return;
                }else{
                    index++;
                }
            }
        }
        if (index <= 10){
            setDynamicPower(index,machineInfo,powerIncomeInfoDto);
            column.setKey("c"+index);
            columns.add(column);
        }
    }

    private void setDynamicPower(int index,MachineInfoDto machineInfo,PowerIncomeInfoDto powerIncomeInfoDto){
        switch (index){
            case 1:
                machineInfo.setC1(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
                break;
            case 2:
                machineInfo.setC2(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
                break;
            case 3:
                machineInfo.setC3(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
                break;
            case 4:
                machineInfo.setC4(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
                break;
            case 5:
                machineInfo.setC5(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
                break;
            case 6:
                machineInfo.setC6(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
                break;
            case 7:
                machineInfo.setC7(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
                break;
            case 8:
                machineInfo.setC8(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
                break;
            case 9:
                machineInfo.setC9(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
                break;
            case 10:
                machineInfo.setC10(powerIncomeInfoDto.getPower() + powerIncomeInfoDto.getUnit());
                break;
        }
    }

    @Override
    public PageResult<SellerMachineInfoDto> getShopMachineListForSeller(SellerMachineVo sellerMachineVo) {
        LeaseShop leaseShop = getShopById();
        if (leaseShop == null){
            //店铺未创建
            return PageResult.success(new ArrayList<>());
        }
        PageHelper.startPage(sellerMachineVo.getPageNum(), sellerMachineVo.getPageSize());
        List<SellerMachineInfoDto> machineInfoDtoList = leaseMachineMapper.getShopMachineListForSeller(sellerMachineVo,leaseShop.getId());
        PageInfo<SellerMachineInfoDto> pageInfo = new PageInfo<>(machineInfoDtoList);
        if (machineInfoDtoList.isEmpty()){
            //不存在矿机
            return PageResult.success(new ArrayList<>());
        }
        PageResult<SellerMachineInfoDto> success = PageResult.success(machineInfoDtoList);
        //获取矿机配置信息
        List<AsicCoinAndAlgoDto> coinAndAlgoList = leaseMachineMapper.getCoinAndAlgoList(success.getRows());
        Map<Long, List<AsicCoinAndAlgoDto>> collect1 = coinAndAlgoList.stream().collect(Collectors.groupingBy(AsicCoinAndAlgoDto::getProductMachineId));
        //价格配置信息
        List<MachinePayTypeDto> machinePriceList = leaseMachineMapper.getMachinePriceList(success.getRows());
        Map<Long, List<MachinePayTypeDto>> collect = machinePriceList.stream().collect(Collectors.groupingBy(MachinePayTypeDto::getProductMachineId));
        //能否上架
        Map<Long, MachineEffectDto> longMachineEffectDtoMap = leaseMachineMapper.checkIsEffect(success.getRows());

        for (SellerMachineInfoDto row : success.getRows()) {
            MachineEffectDto machineEffectDto = longMachineEffectDtoMap.get(row.getId());
            row.setEffect(machineEffectDto != null ? machineEffectDto.getEffect() : 0);
            row.setPriceList(collect.get(row.getId()));
            row.setCoinAndAlgoList(collect1.get(row.getId()));
        }
        success.setTotal(pageInfo.getTotal());
        success.setTotalPage(pageInfo.getPages());
        PageHelper.clearPage();
        return success;
    }


    /**
     * 分页内排序
     * @param shopMachineVo 查询条件
     * @param machineInfoDtoList 钱包信息
     * @return 查询条件
     */
    public List<MachineInfoDto> sorted(List<MachineInfoDto> machineInfoDtoList, ShopMachineVo shopMachineVo){

        if (shopMachineVo.getPriceSort() != null) {
            Comparator<MachineInfoDto> priceComparator = shopMachineVo.getPriceSort() ?
                    Comparator.comparing(MachineInfoDto::getPrice) :
                    Comparator.comparing(MachineInfoDto::getPrice).reversed();
            return  machineInfoDtoList.stream()
                    .sorted(priceComparator)
                    .collect(Collectors.toList());
        } else if (shopMachineVo.getPowerSort() != null) {
            Comparator<MachineInfoDto> powerComparator = shopMachineVo.getPowerSort() ?
                    Comparator.comparing(MachineInfoDto::getTheoryPower) :
                    Comparator.comparing(MachineInfoDto::getTheoryPower).reversed();
            return machineInfoDtoList.stream()
                    .sorted(powerComparator)
                    .collect(Collectors.toList());
        }else {
            return machineInfoDtoList;
        }
    }

    public ShopMachineVo buildQuery(ShopMachineVo shopMachineVo,PayConfigDto payConfigDto){
        if (StringUtils.isEmpty(shopMachineVo.getChain()) && StringUtils.isEmpty(shopMachineVo.getCoin())){
            shopMachineVo.setChain(payConfigDto.getPayChain());
            shopMachineVo.setCoin(payConfigDto.getPayCoin());
        }
        //BigDecimal power = PowerUnit.getPower(shopMachineVo.getUnit()).divide(BigDecimal.valueOf(1000 * 1000),2, RoundingMode.HALF_UP);
        //shopMachineVo.setMaxPower(shopMachineVo.getMaxPower().multiply(power));
        //shopMachineVo.setMinPower(shopMachineVo.getMinPower().multiply(power));
        ////算力设置
        //if (shopMachineVo.getMaxPower().compareTo(shopMachineVo.getMinPower()) < 0){
        //    shopMachineVo.setMaxPower(shopMachineVo.getMinPower());
        //    shopMachineVo.setMinPower(shopMachineVo.getMaxPower());
        //}
        ////功耗设置
        //if (shopMachineVo.getMaxPowerDissipation().compareTo(shopMachineVo.getMinPowerDissipation()) < 0){
        //    shopMachineVo.setMaxPowerDissipation(shopMachineVo.getMinPowerDissipation());
        //    shopMachineVo.setMinPowerDissipation(shopMachineVo.getMaxPowerDissipation());
        //}
        //价格设置
        if (shopMachineVo.getMaxPrice().compareTo(shopMachineVo.getMinPrice()) < 0){

            shopMachineVo.setMaxPrice(shopMachineVo.getMinPrice());
            shopMachineVo.setMinPrice(shopMachineVo.getMaxPrice());
        }
        return shopMachineVo;
    }


    @Override
    @Transactional
    public Result<String> addAsicMachine(AsicMachineParamsVo asicMachineParamsVo) {
        LeaseShop leaseShop = getShopById();
        if (leaseShop == null){
            return Result.fail("添加ASIC矿机失败,未找到商铺,请重试");
        }
        //新增lease_machine主表信息
        LeaseMachine machine = LeaseMachine.builder()
                .hostMac(UuidGeneratorUtil.generateUuidWithoutHyphen())
                .shopId(leaseShop.getId())
                .type(false)
                .maxLeaseDays(asicMachineParamsVo.getMaxLeaseDays())
                .saleNumbers(asicMachineParamsVo.getSaleNumbers())
                .canSaleNumbers(asicMachineParamsVo.getSaleNumbers())
                .build();
        int machineInsert = leaseMachineMapper.insert(machine);

        //新增lease_asic_coin_power_config 配置信息表信息 + lease_machine_price 矿机价格表信息
        if (machineInsert > 0){
            List<LeaseMachineConfig> collect = asicMachineParamsVo.getCoinAndAlgoList().stream().map(
                    coinAndAlgo -> LeaseMachineConfig.builder()
                            .machineId(machine.getId())
                            .name(asicMachineParamsVo.getName())
                            .powerDissipation(asicMachineParamsVo.getPowerDissipation())
                            .coin(coinAndAlgo.getCoin())
                            .algorithm(coinAndAlgo.getAlgorithm())
                            .hashrate(coinAndAlgo.getTheoryPower())
                            .unit(coinAndAlgo.getUnit())
                            .build()
            ).collect(Collectors.toList());

            List<LeaseMachinePrice> collect1 = asicMachineParamsVo.getPriceList().stream()
                    .map(machinePayTypeVo ->
                            LeaseMachinePrice.builder()
                                    .machineId(machine.getId())
                                    .price(machinePayTypeVo.getPrice())
                                    .coin(machinePayTypeVo.getCoin())
                                    .chain(machinePayTypeVo.getChain())
                                    .build()
                    ).collect(Collectors.toList());
            boolean b1 = leaseMachinePriceService.saveBatch(collect1);
            boolean b = leaseMachineConfigService.saveBatch(collect);
            if (!b && !b1){
                throw new MachineException("添加asic矿机币价及算力信息失败");
            }
            return Result.success("添加asic矿机成功");
        }
        return Result.fail("添加ASIC矿机失败,请重试");
    }

    @Override
    @Transactional
    public Result<String> updateAsicMachine(AsicMachineParamsVo asicMachineParamsVo) {
        //修改lease_machine主表信息
        LeaseMachine machine = LeaseMachine.builder()
                .id(asicMachineParamsVo.getId())
                .maxLeaseDays(asicMachineParamsVo.getMaxLeaseDays())
                .saleNumbers(asicMachineParamsVo.getSaleNumbers())
                .state(asicMachineParamsVo.getState())
                .build();
        int machineUpdate = leaseMachineMapper.updateById(machine);
        //修改lease_machine_price 矿机价格表信息 + 修改lease_asic_coin_power_config 配置信息表信息
        if (machineUpdate > 0){

            List<LeaseMachinePrice> collect = asicMachineParamsVo.getPriceList().stream().map(
                    machinePayTypeVo ->
                            LeaseMachinePrice.builder()
                                    .id(machinePayTypeVo.getPayTypeId())
                                    .price(machinePayTypeVo.getPrice())
                                    .build()
            ).collect(Collectors.toList());
            boolean b = leaseMachinePriceService.updateBatchById(collect);
            List<LeaseMachineConfig> collect1 = asicMachineParamsVo.getCoinAndAlgoList().stream().map(coinAndAlgo ->
                    LeaseMachineConfig.builder()
                            .id(coinAndAlgo.getCoinAndPowerId())
                            .machineId(machine.getId())
                            .name(asicMachineParamsVo.getName())
                            .coin(coinAndAlgo.getCoin())
                            .hashrate(coinAndAlgo.getTheoryPower())
                            .algorithm(coinAndAlgo.getAlgorithm())
                            .unit(coinAndAlgo.getUnit())
                            .powerDissipation(asicMachineParamsVo.getPowerDissipation())
                            .build()
            ).collect(Collectors.toList());
            boolean b1 = leaseMachineConfigService.saveOrUpdateBatch(collect1);
            if (!b && !b1){
                throw new MachineException("修改asic矿机币价及算力信息失败");
            }

            return Result.success("修改ASIC矿机成功");
        }
        return Result.fail("修改ASIC矿机失败,请重试");
    }

    @Override
    @Transactional
    public Result<String> updateGpuMachine(List<GpuMachineParamsVo> gpuMachineParamsVoList) {
        //校验能否上架
        for (GpuMachineParamsVo gpuMachineParamsVo : gpuMachineParamsVoList) {

            //修改lease_machine主表信息
            LeaseMachine machine = LeaseMachine.builder()
                    .id(gpuMachineParamsVo.getId())
                    .maxLeaseDays(gpuMachineParamsVo.getMaxLeaseDays())
                    .state(gpuMachineParamsVo.getState())
                    .build();
            int machineUpdate = leaseMachineMapper.updateById(machine);
            //修改lease_machine_price 矿机价格表信息
            if (machineUpdate > 0){
                List<MachinePayTypeVo> priceList = gpuMachineParamsVo.getPriceList();
                for (MachinePayTypeVo machinePayTypeVo : priceList) {
                    LeaseMachinePrice build = LeaseMachinePrice.builder()
                            .id(machinePayTypeVo.getPayTypeId())
                            .price(machinePayTypeVo.getPrice())
                            .chain(machinePayTypeVo.getChain())
                            .coin(machinePayTypeVo.getCoin())
                            .machineId(machine.getId())
                            .build();
                    if (build.getId() == null || build.getId() == 0){
                        leaseMachinePriceMapper.insert(build);
                    }else{
                        leaseMachinePriceMapper.updateById(build);
                    }
                }
            }
        }
        return  Result.success("修改GPU矿机成功") ;
    }


    @Override
    @Transactional
    public Result<String> updateMachineState(MachineStateVo machineStateVo) {
        leaseMachineMapper.updateById(LeaseMachine.builder().id(machineStateVo.getId()).state(machineStateVo.getState()).build());
        return machineStateVo.getState() ? Result.success("下架成功") : Result.success("上架成功");
    }

    @Override
    public Result<String> deleteMachine(BaseVo baseVo) {
        //TODO 删除之前需要判断是否存在订单
        leaseMachineMapper.updateById(LeaseMachine.builder().id(baseVo.getId()).del(true).build());
        //删除售价
        leaseMachinePriceMapper.update(LeaseMachinePrice.builder().del(true).build(),new LambdaQueryWrapper<LeaseMachinePrice>()
                .eq(LeaseMachinePrice::getMachineId,baseVo.getId()));
        //ASIC/GPU 矿机删除配置信息
        leaseMachineConfigMapper.update(LeaseMachineConfig.builder().del(true).build(),
                new LambdaQueryWrapper<LeaseMachineConfig>().eq(LeaseMachineConfig::getMachineId,baseVo.getId()));

        return Result.success("删除成功");
    }


    @Override
    public Result<List<String>> getSupportCoin() {
        List<String> supportCoin = leaseMachineMapper.getSupportCoin();
        return Result.success(supportCoin);
    }

    @Override
    public Result<List<String>> getSupportAlgo(String coin) {
        List<String> supportAlgo = leaseMachineMapper.getSupportAlgo(coin);
        return Result.success(supportAlgo);
    }
}
