package com.njcn.gather.tool.parsepqdif.component;

import com.njcn.gather.tool.parsepqdif.pojo.vo.PqdifParseResponse;
import com.njcn.gather.tool.parsepqdif.pojo.vo.PqdifRecognizeResultVO;
import org.springframework.stereotype.Component;

import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.time.format.DateTimeParseException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 将 parse 方法返回的底层 PQDIF 解析结果转换为业务可识别结构。
 */
@Component
public class PqdifSecondParseComponent {

    private static final String STATUS_SUCCESS = "SUCCESS";
    private static final String STATUS_FAILED = "FAILED";
    private static final String MESSAGE_SUCCESS = "PQDIF二次解析完成";

    private static final DateTimeFormatter STANDARD_DATE_TIME_FORMATTER =
            DateTimeFormatter.ofPattern("yyyy-MM-dd HH:mm:ss");
    private static final Map<Long, PhaseInfo> PHASE_MAP = buildPhaseMap();
    private static final Map<Long, String> MEASUREMENT_MAP = buildMeasurementMap();
    private static final Map<Long, String> UNIT_MAP = buildUnitMap();
    private static final Map<Long, String> SERIES_BASE_TYPE_MAP = buildSeriesBaseTypeMap();

    public PqdifRecognizeResultVO parseRecognizableData(PqdifParseResponse parseResponse) {
        if (parseResponse == null) {
            return failed("parse解析结果不能为空");
        }

        if (!STATUS_SUCCESS.equals(parseResponse.getStatus())) {
            String message = parseResponse.getMessage() == null ? "" : parseResponse.getMessage();
            return failed("parse解析未成功，不能进行二次解析：" + message);
        }

        PqdifRecognizeResultVO result = emptyResult(STATUS_SUCCESS, MESSAGE_SUCCESS);
        List<PqdifParseResponse.ObservationVO> sourceObservations = parseResponse.getObservations();
        if (sourceObservations == null || sourceObservations.isEmpty()) {
            return result;
        }

        for (int observationIndex = 0; observationIndex < sourceObservations.size(); observationIndex++) {
            PqdifParseResponse.ObservationVO sourceObservation = sourceObservations.get(observationIndex);
            result.getObservations().add(parseObservation(sourceObservation, observationIndex, result));
        }

        result.setObservationCount((long) result.getObservations().size());
        return result;
    }

    private PqdifRecognizeResultVO.RecognizedObservationVO parseObservation(
            PqdifParseResponse.ObservationVO source,
            int observationIndex,
            PqdifRecognizeResultVO result) {

        PqdifRecognizeResultVO.RecognizedObservationVO target = new PqdifRecognizeResultVO.RecognizedObservationVO();
        target.setRecordIndex(source == null ? null : source.getRecordIndex());
        target.setName(source == null ? null : source.getName());
        target.setStartTime(source == null ? null : formatStartTime(source.getTimeStartText()));
        target.setChannels(new ArrayList<PqdifRecognizeResultVO.RecognizedChannelVO>());

        if (source == null || source.getChannels() == null || source.getChannels().isEmpty()) {
            return target;
        }

        for (int channelIndex = 0; channelIndex < source.getChannels().size(); channelIndex++) {
            PqdifParseResponse.ChannelInfoVO sourceChannel = source.getChannels().get(channelIndex);
            target.getChannels().add(parseChannel(sourceChannel, observationIndex, channelIndex, result));
            result.setChannelCount(result.getChannelCount() + 1);
        }

        return target;
    }

    private PqdifRecognizeResultVO.RecognizedChannelVO parseChannel(
            PqdifParseResponse.ChannelInfoVO source,
            int observationIndex,
            int channelIndex,
            PqdifRecognizeResultVO result) {

        PqdifRecognizeResultVO.RecognizedChannelVO target = new PqdifRecognizeResultVO.RecognizedChannelVO();
        target.setChannelIndex(source == null ? null : source.getChannelIndex());
        target.setName(source == null ? null : source.getName());
        target.setPhaseId(source == null ? null : source.getPhaseId());
        target.setQuantityMeasuredId(source == null ? null : source.getQuantityMeasuredId());
        target.setQuantityTypeGuid(source == null ? null : source.getQuantityTypeGuid());
        target.setSeries(new ArrayList<PqdifRecognizeResultVO.RecognizedSeriesVO>());

        if (source == null) {
            return target;
        }

        PhaseInfo phaseInfo = PHASE_MAP.get(source.getPhaseId());
        if (phaseInfo == null) {
            addUnknown(result, channelPath(observationIndex, channelIndex), "phaseId", source.getPhaseId(), "未识别的相别ID");
        } else {
            target.setPhaseCode(phaseInfo.getCode());
            target.setPhaseName(phaseInfo.getName());
        }

        String measurementName = MEASUREMENT_MAP.get(source.getQuantityMeasuredId());
        if (measurementName == null) {
            addUnknown(result, channelPath(observationIndex, channelIndex),
                    "quantityMeasuredId", source.getQuantityMeasuredId(), "未识别的测量量ID");
        } else {
            target.setMeasurementName(measurementName);
        }

        if (source.getSeries() == null || source.getSeries().isEmpty()) {
            return target;
        }

        for (int seriesIndex = 0; seriesIndex < source.getSeries().size(); seriesIndex++) {
            PqdifParseResponse.SeriesInfoVO sourceSeries = source.getSeries().get(seriesIndex);
            target.getSeries().add(parseSeries(sourceSeries, observationIndex, channelIndex, seriesIndex, result));
            result.setSeriesCount(result.getSeriesCount() + 1);
        }

        return target;
    }

    private PqdifRecognizeResultVO.RecognizedSeriesVO parseSeries(
            PqdifParseResponse.SeriesInfoVO source,
            int observationIndex,
            int channelIndex,
            int seriesIndex,
            PqdifRecognizeResultVO result) {

        PqdifRecognizeResultVO.RecognizedSeriesVO target = new PqdifRecognizeResultVO.RecognizedSeriesVO();
        if (source == null) {
            return target;
        }

        target.setSeriesIndex(source.getSeriesIndex());
        target.setQuantityUnitsId(source.getQuantityUnitsId());
        target.setQuantityCharacteristicGuid(source.getQuantityCharacteristicGuid());
        target.setValueTypeGuid(source.getValueTypeGuid());
        target.setSeriesBaseType(source.getSeriesBaseType());
        target.setScale(source.getScale());
        target.setOffset(source.getOffset());
        target.setDataStatus(source.getDataStatus());
        target.setDataMessage(source.getDataMessage());
        target.setValueCount(source.getValueCount());
        target.setFirstValues(source.getFirstValues());

        String unitName = UNIT_MAP.get(source.getQuantityUnitsId());
        if (unitName == null) {
            addUnknown(result, seriesPath(observationIndex, channelIndex, seriesIndex),
                    "quantityUnitsId", source.getQuantityUnitsId(), "未识别的单位ID");
        } else {
            target.setUnitName(unitName);
        }

        String dataTypeName = SERIES_BASE_TYPE_MAP.get(source.getSeriesBaseType());
        if (dataTypeName == null) {
            addUnknown(result, seriesPath(observationIndex, channelIndex, seriesIndex),
                    "seriesBaseType", source.getSeriesBaseType(), "未识别的Series基础类型");
        } else {
            target.setDataTypeName(dataTypeName);
        }

        return target;
    }

    private PqdifRecognizeResultVO failed(String message) {
        return emptyResult(STATUS_FAILED, message);
    }

    private String formatStartTime(String timeStartText) {
        if (timeStartText == null || timeStartText.trim().isEmpty()) {
            return timeStartText;
        }
        try {
            return LocalDateTime.parse(timeStartText.trim()).format(STANDARD_DATE_TIME_FORMATTER);
        } catch (DateTimeParseException e) {
            return timeStartText;
        }
    }

    private PqdifRecognizeResultVO emptyResult(String status, String message) {
        PqdifRecognizeResultVO result = new PqdifRecognizeResultVO();
        result.setStatus(status);
        result.setMessage(message);
        result.setObservationCount(0L);
        result.setChannelCount(0L);
        result.setSeriesCount(0L);
        result.setObservations(new ArrayList<PqdifRecognizeResultVO.RecognizedObservationVO>());
        result.setUnknownItems(new ArrayList<PqdifRecognizeResultVO.UnknownItemVO>());
        return result;
    }

    private void addUnknown(PqdifRecognizeResultVO result, String path, String fieldName, Object fieldValue, String message) {
        if (fieldValue == null) {
            return;
        }
        PqdifRecognizeResultVO.UnknownItemVO item = new PqdifRecognizeResultVO.UnknownItemVO();
        item.setPath(path);
        item.setFieldName(fieldName);
        item.setFieldValue(String.valueOf(fieldValue));
        item.setMessage(message);
        result.getUnknownItems().add(item);
    }

    private String channelPath(int observationIndex, int channelIndex) {
        return "observations[" + observationIndex + "].channels[" + channelIndex + "]";
    }

    private String seriesPath(int observationIndex, int channelIndex, int seriesIndex) {
        return channelPath(observationIndex, channelIndex) + ".series[" + seriesIndex + "]";
    }

    private static Map<Long, PhaseInfo> buildPhaseMap() {
        Map<Long, PhaseInfo> map = new HashMap<Long, PhaseInfo>();
        map.put(0L, new PhaseInfo("UNKNOWN", "未知相别"));
        map.put(1L, new PhaseInfo("A", "A相"));
        map.put(2L, new PhaseInfo("B", "B相"));
        map.put(3L, new PhaseInfo("C", "C相"));
        map.put(4L, new PhaseInfo("N", "中性线"));
        map.put(5L, new PhaseInfo("AB", "AB线电压"));
        map.put(6L, new PhaseInfo("BC", "BC线电压"));
        map.put(7L, new PhaseInfo("CA", "CA线电压"));
        return map;
    }

    private static Map<Long, String> buildMeasurementMap() {
        Map<Long, String> map = new HashMap<Long, String>();
        map.put(0L, "电压");
        map.put(1L, "电流");
        map.put(2L, "频率");
        map.put(3L, "有功功率");
        map.put(4L, "无功功率");
        map.put(5L, "视在功率");
        map.put(6L, "功率因数");
        return map;
    }

    private static Map<Long, String> buildUnitMap() {
        Map<Long, String> map = new HashMap<Long, String>();
        map.put(27L, "A");
        map.put(29L, "V");
        map.put(32L, "Hz");
        map.put(38L, "W");
        map.put(39L, "var");
        map.put(40L, "VA");
        map.put(41L, "%");
        return map;
    }

    private static Map<Long, String> buildSeriesBaseTypeMap() {
        Map<Long, String> map = new HashMap<Long, String>();
        map.put(1L, "DOUBLE");
        map.put(2L, "INTEGER");
        map.put(3L, "BOOLEAN");
        map.put(4L, "TEXT");
        return map;
    }

    private static class PhaseInfo {
        private final String code;
        private final String name;

        private PhaseInfo(String code, String name) {
            this.code = code;
            this.name = name;
        }

        private String getCode() {
            return code;
        }

        private String getName() {
            return name;
        }
    }
}
