package com.njcn.gather.result.util;

import com.njcn.gather.report.pojo.enums.ItemReportKeyEnum;
import com.njcn.gather.script.pojo.vo.PqScriptDtlDataVO;
import com.njcn.gather.storage.pojo.po.SimAndDigNonHarmonicResult;
import org.junit.Test;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static org.junit.Assert.assertEquals;

public class PowerResultAssemblerTest {

    @Test
    public void assembleRows_mergesTotalPowerResultsBySort() {
        List<SimAndDigNonHarmonicResult> results = Arrays.asList(
                total("TotW", 14, "{\"data\": -1079.364014, \"unit\": \"%\", \"isData\": 1, \"radius\": \"-0.5~0.5\", \"errorData\": -0.058888, \"resultData\": -1080}"),
                total("TotVAr", 14, "{\"data\": 12.16591, \"isData\": 5, \"resultData\": 0}"),
                total("TotVA", 14, "{\"data\": 1079.463013, \"isData\": 5, \"resultData\": 1080}")
        );

        List<Map<String, String>> rows = PowerResultAssembler.assembleRows(results);

        assertEquals(1, rows.size());
        Map<String, String> row = rows.get(0);
        assertEquals("-1079.3640", row.get(ItemReportKeyEnum.ACTIVE_POWER.getKey()));
        assertEquals("12.1659", row.get(ItemReportKeyEnum.REACTIVE_POWER.getKey()));
        assertEquals("1079.4630", row.get(ItemReportKeyEnum.APPARENT_POWER.getKey()));
        assertEquals("-1080.0000", row.get(ItemReportKeyEnum.STANDARD.getKey()));
        assertEquals("合格", row.get(ItemReportKeyEnum.RESULT.getKey()));
    }

    @Test
    public void assembleRows_sumsPhasePowerWhenTotalPowerIsAbsent() {
        SimAndDigNonHarmonicResult result = new SimAndDigNonHarmonicResult();
        result.setAdType("W");
        result.setSort(15);
        result.setAValue("{\"data\": 100.1, \"isData\": 1, \"resultData\": 100}");
        result.setBValue("{\"data\": 200.2, \"isData\": 1, \"resultData\": 200}");
        result.setCValue("{\"data\": 300.3, \"isData\": 1, \"resultData\": 300}");

        List<Map<String, String>> rows = PowerResultAssembler.assembleRows(Arrays.asList(result));

        assertEquals(1, rows.size());
        assertEquals("600.6000", rows.get(0).get(ItemReportKeyEnum.ACTIVE_POWER.getKey()));
    }

    @Test
    public void assembleRows_prefersTotalPowerWhenTotalAndPhaseBothExist() {
        SimAndDigNonHarmonicResult total = total("TotW", 16,
                "{\"data\": 1000.0, \"isData\": 1, \"resultData\": 1000}");
        SimAndDigNonHarmonicResult phases = new SimAndDigNonHarmonicResult();
        phases.setAdType("W");
        phases.setSort(16);
        phases.setAValue("{\"data\": 1.0, \"isData\": 1, \"resultData\": 1}");
        phases.setBValue("{\"data\": 2.0, \"isData\": 1, \"resultData\": 2}");
        phases.setCValue("{\"data\": 3.0, \"isData\": 1, \"resultData\": 3}");

        List<Map<String, String>> rows = PowerResultAssembler.assembleRows(Arrays.asList(total, phases));

        assertEquals(1, rows.size());
        assertEquals("1000.0000", rows.get(0).get(ItemReportKeyEnum.ACTIVE_POWER.getKey()));
    }

    @Test
    public void assembleRows_usesTotalPowerAsPrimaryWhenPhaseResultComesFirst() {
        SimAndDigNonHarmonicResult phases = new SimAndDigNonHarmonicResult();
        phases.setAdType("W");
        phases.setSort(17);
        phases.setAValue("{\"data\": 1.0, \"isData\": 1, \"resultData\": 1}");
        phases.setBValue("{\"data\": 2.0, \"isData\": 1, \"resultData\": 2}");
        phases.setCValue("{\"data\": 3.0, \"isData\": 1, \"resultData\": 3}");
        SimAndDigNonHarmonicResult total = total("TotW", 17,
                "{\"data\": 1000.0, \"isData\": 1, \"resultData\": 2000}");

        List<Map<String, String>> rows = PowerResultAssembler.assembleRows(Arrays.asList(phases, total));

        assertEquals(1, rows.size());
        assertEquals("1000.0000", rows.get(0).get(ItemReportKeyEnum.ACTIVE_POWER.getKey()));
        assertEquals("2000.0000", rows.get(0).get(ItemReportKeyEnum.STANDARD.getKey()));
        assertEquals("1000.0000", rows.get(0).get(ItemReportKeyEnum.TEST.getKey()));
    }

    @Test
    public void assembleRows_prefersTotalPowerFactorWhenTotalAndPhaseBothExist() {
        SimAndDigNonHarmonicResult total = total("TotPF", 18,
                "{\"data\": 0.9900, \"isData\": 1, \"resultData\": 1.0}");
        SimAndDigNonHarmonicResult phases = new SimAndDigNonHarmonicResult();
        phases.setAdType("PF");
        phases.setSort(18);
        phases.setAValue("{\"data\": 0.7, \"isData\": 1, \"resultData\": 1.0}");
        phases.setBValue("{\"data\": 0.8, \"isData\": 1, \"resultData\": 1.0}");
        phases.setCValue("{\"data\": 0.9, \"isData\": 1, \"resultData\": 1.0}");

        List<Map<String, String>> rows = PowerResultAssembler.assembleRows(Arrays.asList(total, phases));

        assertEquals(1, rows.size());
        assertEquals("0.9900", rows.get(0).get(ItemReportKeyEnum.POWER_FACTOR.getKey()));
    }

    @Test
    public void assembleRows_defaultsMissingPowerKeysToSlash() {
        SimAndDigNonHarmonicResult total = total("TotW", 18,
                "{\"data\": 1000.0, \"isData\": 1, \"resultData\": 1000}");

        List<Map<String, String>> rows = PowerResultAssembler.assembleRows(Arrays.asList(total));

        assertEquals(1, rows.size());
        assertEquals("/", rows.get(0).get(ItemReportKeyEnum.STANDARD_V.getKey()));
        assertEquals("/", rows.get(0).get(ItemReportKeyEnum.STANDARD_A.getKey()));
        assertEquals("/", rows.get(0).get(ItemReportKeyEnum.POWER_FACTOR.getKey()));
    }

    @Test
    public void assembleRows_fillsStandardSourceValuesFromScriptDetailsPreferringPhaseA() {
        SimAndDigNonHarmonicResult total = total("TotW", 19,
                "{\"data\": 1000.0, \"isData\": 1, \"resultData\": 1000}");
        List<PqScriptDtlDataVO> scriptDetails = Arrays.asList(
                scriptDetail(19, "VOL", "B", 58.0, 120.0),
                scriptDetail(19, "CUR", "B", 6.0, 90.0),
                scriptDetail(19, "VOL", "A", 57.74, 0.0),
                scriptDetail(19, "CUR", "A", 5.0, -30.0)
        );

        List<Map<String, String>> rows = PowerResultAssembler.assembleRows(Arrays.asList(total), scriptDetails);

        assertEquals(1, rows.size());
        assertEquals("57.7400", rows.get(0).get(ItemReportKeyEnum.STANDARD_V.getKey()));
        assertEquals("5.0000", rows.get(0).get(ItemReportKeyEnum.STANDARD_I.getKey()));
        assertEquals("0.0000", rows.get(0).get(ItemReportKeyEnum.STANDARD_U_ANGLE.getKey()));
        assertEquals("-30.0000", rows.get(0).get(ItemReportKeyEnum.STANDARD_I_ANGLE.getKey()));
    }

    @Test
    public void assembleRows_fallsBackToPhaseBForStandardSourceValuesWhenPhaseAIsAbsent() {
        SimAndDigNonHarmonicResult total = total("TotW", 20,
                "{\"data\": 1000.0, \"isData\": 1, \"resultData\": 1000}");
        List<PqScriptDtlDataVO> scriptDetails = Arrays.asList(
                scriptDetail(20, "VOL", "C", 59.0, 240.0),
                scriptDetail(20, "CUR", "C", 7.0, 210.0),
                scriptDetail(20, "VOL", "B", 58.0, 120.0),
                scriptDetail(20, "CUR", "B", 6.0, 90.0)
        );

        List<Map<String, String>> rows = PowerResultAssembler.assembleRows(Arrays.asList(total), scriptDetails);

        assertEquals(1, rows.size());
        assertEquals("58.0000", rows.get(0).get(ItemReportKeyEnum.STANDARD_V.getKey()));
        assertEquals("6.0000", rows.get(0).get(ItemReportKeyEnum.STANDARD_I.getKey()));
        assertEquals("120.0000", rows.get(0).get(ItemReportKeyEnum.STANDARD_U_ANGLE.getKey()));
        assertEquals("90.0000", rows.get(0).get(ItemReportKeyEnum.STANDARD_I_ANGLE.getKey()));
    }

    private SimAndDigNonHarmonicResult total(String code, Integer sort, String tValue) {
        SimAndDigNonHarmonicResult result = new SimAndDigNonHarmonicResult();
        result.setAdType(code);
        result.setSort(sort);
        result.setTValue(tValue);
        return result;
    }

    private PqScriptDtlDataVO scriptDetail(Integer sort, String valueType, String phase, Double value, Double angle) {
        PqScriptDtlDataVO detail = new PqScriptDtlDataVO();
        detail.setScriptIndex(sort);
        detail.setValueType(valueType);
        detail.setPhase(phase);
        detail.setValue(value);
        detail.setAngle(angle);
        return detail;
    }
}
