package com.njcn.gather.freqConverter.service.impl;

import cn.hutool.core.util.IdUtil;
import com.baomidou.mybatisplus.extension.conditions.query.LambdaQueryChainWrapper;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.njcn.db.mybatisplus.handler.DynamicTableNameHandler;
import com.njcn.gather.dip.service.IPqDipDataService;
import com.njcn.gather.freqConverter.mapper.FreqConverterStatusMapper;
import com.njcn.gather.freqConverter.pojo.po.FreqConverterStatus;
import com.njcn.gather.freqConverter.pojo.po.PqFreqConverterTestRes;
import com.njcn.gather.freqConverter.pojo.vo.TolerantPointVO;
import com.njcn.gather.freqConverter.service.IFreqConverterService;
import com.njcn.gather.freqConverter.service.IPqFreqConverterConfigService;
import com.njcn.gather.freqConverter.service.IPqFreqConverterTestResService;
import lombok.AllArgsConstructor;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 变频器状态数据Service实现类
 * <p>
 * 实现变频器状态数据的存储、查询和清理功能。
 * 当数据量超过阈值时，自动清理无效或过期数据，避免内存和数据库资源浪费。
 * </p>
 *
 * @author CN_Gather Detection Team
 * @version 1.0
 * @since 2026
 */
@Service
@AllArgsConstructor
public class FreqConverterServiceImpl extends ServiceImpl<FreqConverterStatusMapper, FreqConverterStatus> implements IFreqConverterService {
    private final IPqFreqConverterConfigService pqFreqConverterConfigService;
    private final IPqDipDataService dipDataService;
    private final IPqFreqConverterTestResService pqFreqConverterTestResService;


    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean saveFreqConverterStatus(Integer suffix, FreqConverterStatus status) {
        if (status.getId() == null) {
            status.setId(IdUtil.fastSimpleUUID());
        }
        DynamicTableNameHandler.setTableName(PqFreqConverterConfigServiceImpl.PQ_FREQ_CONVERTER_STATUS_TB_PREFIX + suffix);
        boolean result = this.save(status);
        DynamicTableNameHandler.remove();
        return result;
    }

    @Override
    public List<FreqConverterStatus> listStatusData(String converterId) {
        Integer suffix = pqFreqConverterConfigService.getSuffix(converterId);

        DynamicTableNameHandler.setTableName(PqFreqConverterConfigServiceImpl.PQ_FREQ_CONVERTER_STATUS_TB_PREFIX + suffix);
        LambdaQueryChainWrapper<FreqConverterStatus> wrapper = this.lambdaQuery().orderByAsc(FreqConverterStatus::getTimestamp);
        List<FreqConverterStatus> result = wrapper.list();
        DynamicTableNameHandler.remove();

        return result;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public void clearAllData(Integer suffix) {
        DynamicTableNameHandler.setTableName(PqFreqConverterConfigServiceImpl.PQ_FREQ_CONVERTER_STATUS_TB_PREFIX + suffix);
        this.remove(null);
        DynamicTableNameHandler.remove();
    }

    @Override
    public List<TolerantPointVO> getDipPoints(String converterId) {
        Integer suffix = pqFreqConverterConfigService.getSuffix(converterId);

        DynamicTableNameHandler.setTableName(PqFreqConverterConfigServiceImpl.PQ_FREQ_CONVERTER_TEST_RES_TB_PREFIX + suffix);
        List<PqFreqConverterTestRes> pqFreqConverterTestResList = pqFreqConverterTestResService.list();
        DynamicTableNameHandler.remove();
        List<TolerantPointVO> result = pqFreqConverterTestResList.stream().map(item -> {
                    TolerantPointVO tolerantPointVO = new TolerantPointVO();
                    tolerantPointVO.setDurationMs(item.getDurationMs());
                    tolerantPointVO.setResidualVoltage(item.getResidualVoltage());
                    tolerantPointVO.setTolerant(item.getTolerant());
                    tolerantPointVO.setTime(item.getTime());
                    return tolerantPointVO;
                })
                .sorted(Comparator.comparingInt(TolerantPointVO::getDurationMs))
                .sorted(Comparator.comparingDouble(TolerantPointVO::getResidualVoltage)).collect(Collectors.toList());

        return result;
    }

    @Override
    public List<FreqConverterStatus> getDipDurationStatusData(Integer suffix, LocalDateTime startTime, LocalDateTime endTime) {
        DynamicTableNameHandler.setTableName(PqFreqConverterConfigServiceImpl.PQ_FREQ_CONVERTER_STATUS_TB_PREFIX + suffix);
        List<FreqConverterStatus> result = this.lambdaQuery()
                .between(FreqConverterStatus::getTimestamp, startTime, endTime)
                .orderByAsc(FreqConverterStatus::getTimestamp)
                .list();
        DynamicTableNameHandler.remove();
        return result;
    }

    @Override
    public FreqConverterStatus getLastStatusData(Integer suffix, LocalDateTime startTime) {
        DynamicTableNameHandler.setTableName(PqFreqConverterConfigServiceImpl.PQ_FREQ_CONVERTER_STATUS_TB_PREFIX + suffix);
        FreqConverterStatus one = this.lambdaQuery().le(FreqConverterStatus::getTimestamp, startTime)
                .orderByDesc(FreqConverterStatus::getTimestamp)
                .last("limit 1")
                .one();
        DynamicTableNameHandler.remove();
        return one;
    }

    @Override
    public List<TolerantPointVO> getFeaturesScurvePoints(String converterId) {
        List<TolerantPointVO> dipPoints = this.getDipPoints(converterId);
        if (dipPoints == null || dipPoints.isEmpty()) {
            return new ArrayList<>();
        }

        Map<Integer, List<TolerantPointVO>> durationPointMap = dipPoints.stream()
                .collect(Collectors.groupingBy(TolerantPointVO::getDurationMs, TreeMap::new, Collectors.toList()));
        if (durationPointMap.size() < 2) {
            return new ArrayList<>();
        }

        List<TolerantPointVO> result = new ArrayList<>();

        TolerantPointVO firstPoint = new TolerantPointVO();

        List<Integer> keyList = durationPointMap.keySet().stream().collect(Collectors.toList());
        Integer i1 = keyList.get(0);
        List<TolerantPointVO> tolerantPointVOS1 = durationPointMap.get(i1);
        Collections.sort(tolerantPointVOS1, Comparator.comparing(TolerantPointVO::getResidualVoltage));
        TolerantPointVO tolerantPointVO1 = tolerantPointVOS1.get(0);

        Integer i2 = keyList.get(1);
        List<TolerantPointVO> tolerantPointVOS2 = durationPointMap.get(i2);
        Collections.sort(tolerantPointVOS2, Comparator.comparing(TolerantPointVO::getResidualVoltage));
        TolerantPointVO tolerantPointVO2 = tolerantPointVOS2.get(0);

        firstPoint.setDurationMs((i1 + i2) / 2);
        firstPoint.setResidualVoltage((tolerantPointVO1.getResidualVoltage() + tolerantPointVO2.getResidualVoltage()) / 2D);
        firstPoint.setTolerant(2);
        result.add(firstPoint);

        durationPointMap.entrySet().stream()
                .forEach(entry -> {
                    List<TolerantPointVO> sameDurationPoints = entry.getValue().stream()
                            .sorted(Comparator.comparing(TolerantPointVO::getResidualVoltage, Comparator.reverseOrder()))
                            .collect(Collectors.toList());

                    for (int index = 0; index < sameDurationPoints.size() - 1; index++) {
                        TolerantPointVO currentPoint = sameDurationPoints.get(index);
                        TolerantPointVO nextPoint = sameDurationPoints.get(index + 1);
                        if (!Objects.equals(currentPoint.getTolerant(), nextPoint.getTolerant())) {
                            TolerantPointVO featurePoint = new TolerantPointVO();
                            featurePoint.setDurationMs(entry.getKey());
                            featurePoint.setResidualVoltage((currentPoint.getResidualVoltage() + nextPoint.getResidualVoltage()) / 2D);
                            featurePoint.setTolerant(2);
                            result.add(featurePoint);
                            break;
                        }
                    }
                });

        return result;
    }
}
