package com.tongran.rocketmq.service.impl;

import com.tongran.common.core.utils.*;
import com.tongran.rocketmq.domain.InitialDiskInfo;
import com.tongran.rocketmq.mapper.InitialDiskInfoMapper;
import com.tongran.rocketmq.service.IAllDiskNameService;
import com.tongran.rocketmq.service.IInitialDiskInfoService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Isolation;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 磁盘监控信息Service业务层处理
 * 
 * @author tongran
 * @date 2025-08-25
 */
@Service
@Slf4j
public class InitialDiskInfoServiceImpl implements IInitialDiskInfoService 
{
    @Autowired
    private InitialDiskInfoMapper initialDiskInfoMapper;
    @Autowired
    private IAllDiskNameService allDiskNameService;
    private final static String TABLE_PREFIX = "initial_disk_info";

    /**
     * 查询磁盘监控信息
     * 
     * @param id 磁盘监控信息主键
     * @return 磁盘监控信息
     */
    @Override
    public InitialDiskInfo selectInitialDiskInfoById(Long id)
    {
        return initialDiskInfoMapper.selectInitialDiskInfoById(id);
    }

    /**
     * 查询磁盘监控信息列表
     * 
     * @param initialDiskInfo 磁盘监控信息
     * @return 磁盘监控信息
     */
    @Override
    public List<InitialDiskInfo> selectInitialDiskInfoList(InitialDiskInfo initialDiskInfo)
    {
        return initialDiskInfoMapper.selectInitialDiskInfoList(initialDiskInfo);
    }

    /**
     * 新增磁盘监控信息
     * 
     * @param initialDiskInfo 磁盘监控信息
     * @return 结果
     */
    @Override
    public int insertInitialDiskInfo(InitialDiskInfo initialDiskInfo)
    {
        initialDiskInfo.setCreateTime(DateUtils.getNowDate());
        return initialDiskInfoMapper.insertInitialDiskInfo(initialDiskInfo);
    }

    /**
     * 修改磁盘监控信息
     * 
     * @param initialDiskInfo 磁盘监控信息
     * @return 结果
     */
    @Override
    public int updateInitialDiskInfo(InitialDiskInfo initialDiskInfo)
    {
        initialDiskInfo.setUpdateTime(DateUtils.getNowDate());
        return initialDiskInfoMapper.updateInitialDiskInfo(initialDiskInfo);
    }

    /**
     * 批量删除磁盘监控信息
     * 
     * @param ids 需要删除的磁盘监控信息主键
     * @return 结果
     */
    @Override
    public int deleteInitialDiskInfoByIds(Long[] ids)
    {
        return initialDiskInfoMapper.deleteInitialDiskInfoByIds(ids);
    }

    /**
     * 删除磁盘监控信息信息
     * 
     * @param id 磁盘监控信息主键
     * @return 结果
     */
    @Override
    public int deleteInitialDiskInfoById(Long id)
    {
        return initialDiskInfoMapper.deleteInitialDiskInfoById(id);
    }
    /**
     * 批量新增磁盘监控信息
     *
     * @param list 磁盘监控信息集合
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class, isolation = Isolation.READ_COMMITTED)
    public int batchInsertInitialDiskInfo(List<InitialDiskInfo> list, Date createTime) {
        if (list == null || list.isEmpty()) {
            return 0;
        }
        // 按表名分组批量插入
        Map<String, List<InitialDiskInfo>> groupedData = list.stream()
                .map(data -> {
                    try {
                        InitialDiskInfo processed = new InitialDiskInfo();
                        BeanUtils.copyProperties(data,processed);
                        if (data.getCreateTime() == null) {
                            data.setCreateTime(DateUtils.getNowDate());
                        }
                        processed.setTableName(TableSubUtil.getTableName(createTime, TABLE_PREFIX));
                        return processed;
                    } catch (Exception e){
                        log.error("数据处理失败",e.getMessage());
                        return null;
                    }
                }).collect(Collectors.groupingBy(
                        InitialDiskInfo::getTableName,
                        LinkedHashMap::new, // 保持插入顺序
                        Collectors.toList()));

        groupedData.forEach((tableName, dataList) -> {
            try {
                InitialDiskInfo data = new InitialDiskInfo();
                data.setTableName(tableName);
                data.setList(dataList);
                initialDiskInfoMapper.batchInsertInitialDiskInfo(data);
                // 记录磁盘名称
                allDiskNameService.batchInsertAllDistName(dataList);
            } catch (Exception e) {
                log.error("表{}插入失败", tableName, e);
                throw new RuntimeException("批量插入失败", e);
            }
        });
        return 1;
    }
    /**
     * 磁盘设备/dev/sda基础信息
     * @param initialDiskInfo
     * @return
     */
    @Override
    public InitialDiskInfo getDistDetailsMsg(InitialDiskInfo initialDiskInfo) {
        String tableName = TableSubUtil.getTableName(DateUtils.getNowDate(), TABLE_PREFIX);
        initialDiskInfo.setTableName(tableName);
        InitialDiskInfo info = initialDiskInfoMapper.getDistDetailsMsgByClientId(initialDiskInfo);
        if(info != null){
            long gbUnit = 1024L * 1024 * 1024;
            info.setTotal(info.getTotal() / gbUnit);
            info.setReadTimesStr(UnitChangeUtil.formatWithUnit(info.getReadTimes()));
            info.setWriteTimesStr(UnitChangeUtil.formatWithUnit(info.getWriteTimes()));
            info.setReadBytesStr(UnitChangeUtil.formatWithKbMin(info.getReadBytes()));
            info.setWriteBytesStr(UnitChangeUtil.formatWithKbMin(info.getWriteBytes()));
        }
        return info;
    }
    @Override
    public InitialDiskInfo getDiskTotal(InitialDiskInfo initialDiskInfo) {
        String tableName = TableSubUtil.getTableName(DateUtils.getNowDate(), TABLE_PREFIX);
        initialDiskInfo.setTableName(tableName);
        InitialDiskInfo info = initialDiskInfoMapper.getDiskTotal(initialDiskInfo);
        if(info != null){
            long gbUnit = 1024L * 1024 * 1024;
            info.setTotal(info.getTotal() / gbUnit);
        }else {
            return new InitialDiskInfo();
        }
        return info;
    }
    /**
     * 分表查询硬盘信息
     * @param queryParam
     * @return
     */
    public List<InitialDiskInfo> getDistInfoSharding(InitialDiskInfo queryParam) {
        // 获取涉及的表名
        Set<String> tableNames = TableSubUtil.getExistingTableNamesBetween(queryParam.getStartTime(), queryParam.getEndTime(), TABLE_PREFIX);

        // 并行查询各表
        return tableNames.parallelStream()
                .flatMap(tableName -> {
                    InitialDiskInfo condition = new InitialDiskInfo();
                    condition.setTableName(tableName);
                    condition.setClientId(queryParam.getClientId());
                    condition.setName(queryParam.getName());
                    condition.setType(queryParam.getType());
                    condition.setStartTime(queryParam.getStartTime());
                    condition.setEndTime(queryParam.getEndTime());
                    return initialDiskInfoMapper.selectInitialDiskInfoListByCondition(condition).stream();
                })
                .collect(Collectors.toList());
    }
    /**
     * /dev/sda读写速率(KB/s)
     * @param initialDiskInfo
     * @return
     */
    @Override
    public Map<String, Object> rwSpeedEcharts(InitialDiskInfo initialDiskInfo) {
        List<InitialDiskInfo> list = getDistInfoSharding(initialDiskInfo);
        Map<String, Function<InitialDiskInfo, ?>> extractors = new LinkedHashMap<>();
        extractors.put("readSpeedData", info -> info.getReadSpeed() / 1024.0);
        extractors.put("writeSpeedData", info -> info.getWriteSpeed() / 1024.0);
        return EchartsDataUtils.buildEchartsData(list, InitialDiskInfo::getCreateTime, extractors);
    }
    /**
     * /dev/sda读写次数
     * @param initialDiskInfo
     * @return
     */
    @Override
    public Map<String, Object> rwTimesEcharts(InitialDiskInfo initialDiskInfo) {
        List<InitialDiskInfo> list = getDistInfoSharding(initialDiskInfo);
        Map<String, Function<InitialDiskInfo, ?>> extractors = new LinkedHashMap<>();
        extractors.put("readTimesData", info -> info.getReadTimes());
        extractors.put("writeTimesData", info -> info.getWriteTimes());
        return EchartsDataUtils.buildEchartsData(list, InitialDiskInfo::getCreateTime, extractors);
    }
    /**
     * /dev/sda读写字节
     * @param initialDiskInfo
     * @return
     */
    @Override
    public Map<String, Object> rwBytesEcharts(InitialDiskInfo initialDiskInfo) {
        List<InitialDiskInfo> list = getDistInfoSharding(initialDiskInfo);
        Map<String, Function<InitialDiskInfo, ?>> extractors = new LinkedHashMap<>();
        extractors.put("readBytesData", info -> info.getReadBytes());
        extractors.put("writeBytesData", info -> info.getWriteBytes());
        return EchartsDataUtils.buildEchartsData(list, InitialDiskInfo::getCreateTime, extractors);
    }
    @Override
    public Map<String, Object> usedSpaceEcharts(InitialDiskInfo initialDiskInfo) {
        initialDiskInfo.setType("HDD");
        List<InitialDiskInfo> list = getDistInfoSharding(initialDiskInfo);
        String unit = "Kb";
        if(list != null && !list.isEmpty()){
            Long totalUsedSpace = 0L;
            for (InitialDiskInfo diskInfo : list) {
                totalUsedSpace += diskInfo.getUsedSpace();
            }
            Long avgUsedSpace = totalUsedSpace/list.size();
            unit = SpeedUtils.determineUnitByValue(avgUsedSpace);
        }
        // 计算单位
        if (initialDiskInfo.getUnit() != null) {
            unit = initialDiskInfo.getUnit();
        }
        BigDecimal divisor = SpeedUtils.get1024Divisor(unit);
        Map<String, Function<InitialDiskInfo, ?>> extractors = new LinkedHashMap<>();
        extractors.put("usedSpace", info -> {
            BigDecimal usedSpace = new BigDecimal(info.getUsedSpace());
            return usedSpace.divide(divisor, 0, RoundingMode.DOWN).longValue();
        });
        Map<String, Object> resultMap = EchartsDataUtils.buildEchartsDataAutoPadding(
                list,InitialDiskInfo::getCreateTime, extractors, initialDiskInfo.getStartTime(), initialDiskInfo.getEndTime());
        resultMap.put("unit", unit);
        return resultMap;
    }
    /**
     * 获取指定服务器的磁盘名称
     * @param initialDiskInfo
     * @return
     */
    @Override
    public List<Map> getAllDistName(InitialDiskInfo initialDiskInfo) {
        return initialDiskInfoMapper.getAllDistName(initialDiskInfo);
    }
}
