package cz.moneta.test.harness.endpoints.ilodsserver;

import cz.moneta.test.harness.connectors.IlodsServerConnector;
import cz.moneta.test.harness.constants.HarnessConfigConstants;
import cz.moneta.test.harness.context.StoreAccessor;
import cz.moneta.test.harness.endpoints.CommonEndpoint;
import cz.moneta.test.harness.support.mwf.TifClient;
import cz.moneta.test.harness.endpoints.ods.OdsEndpoint;
import cz.moneta.test.harness.exception.HarnessException;
import itSodTesting.sharedResources.objects.dataTransfer.IlodsServerAction;
import itSodTesting.sharedResources.objects.dataTransfer.IlodsServerEnvironmentList;
import itSodTesting.sharedResources.objects.dataTransfer.IlodsServerRequestType;
import itSodTesting.sharedResources.objects.dataTransfer.ObjectTransferToClient;
import itSodTesting.sharedResources.objects.dataTransfer.ObjectTransferToServer;
import itSodTesting.sharedResources.objects.ilods.enumerations.IlApplTp;
import itSodTesting.sharedResources.objects.ilods.enumerations.IlBusProdClass;
import itSodTesting.sharedResources.objects.ilods.enumerations.IlSubType;
import itSodTesting.sharedResources.objects.ilods.enumerations.IlType;
import itSodTesting.sharedResources.objects.ilods.odsDataContainers.FlxData;
import itSodTesting.sharedResources.objects.ilods.odsDataContainers.UniPtInfolimitData2;
import itSodTesting.sharedResources.objects.ilods.odsDataContainers.UniPtScData;
import itSodTesting.sharedResources.objects.ilods.odsDataContainers.UniPtSegmData;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Collections;
import java.util.Map;
import java.util.Set;
import java.util.stream.Collectors;

public class IlodsServerEndpoint extends CommonEndpoint {

    private static final Logger logger = LogManager.getLogger(IlodsServerEndpoint.class);

    private IlodsServerConnector connector;
    private IlodsServerEnvironmentList environment;
    private StoreAccessor store;

    public IlodsServerEndpoint(StoreAccessor store) {
        super(store);
        this.store = store;
        this.environment = IlodsServerEnvironmentList.findEnvironment(store.getConfig(HarnessConfigConstants.ENVIRONMENT_TYPE));
        this.connector = new IlodsServerConnector(environment);
    }

    private ObjectTransferToClient sendRequest(ObjectTransferToServer data) {
        data.setSrcSysLogId(store.getGlobal(HarnessConfigConstants.TEST_UNIQUE_ID));
        return connector.sendRequest(data);
    }

    public String sendTestRequest() {
        ObjectTransferToServer data = new ObjectTransferToServer(IlodsServerAction.TEST);
        ObjectTransferToClient response = sendRequest(data);
        return (String) response.getObject("TestString");
    }

    public String setScore(String scoreId, String rcNum, String icoNum) {
        return setScore(scoreId, 999.0, 999.0, rcNum, icoNum);
    }

    public String setScore(String scoreId, double scTot, double scNoBeh, String rcNum, String icoNum) {
        OdsEndpoint ods = (OdsEndpoint) store.getEndpoint(OdsEndpoint.class);
        if (ods.checkScoreCardId(scoreId) == false) {
            throw new IllegalStateException("The set score card (" + scoreId + ") doesn't exist!");
        }

        UniPtScData scData = new UniPtScData();
        scData.setScTpCode(scoreId);
        scData.setUniPtKey(ods.getUniPtKey(rcNum, icoNum));
        scData.setScTot(scTot);
        scData.setScNoBeh(scNoBeh);
        scData.normalizeData(environment);

        ObjectTransferToServer data = new ObjectTransferToServer(IlodsServerAction.ODS_SET_SCORE);
        data.addObject("UNI_PT_SC_DATA", scData);

        ObjectTransferToClient response = sendRequest(data);
        UniPtScData respUniPtScData = (UniPtScData) response.getObject("UNI_PT_SC_DATA");
        String errorCode = respUniPtScData.getErrorCode();
        logger.info("Set score result: " + (errorCode.equals("0") ? "OK" : "ERROR"));
        return errorCode;
    }

    public String setTurnovers(String accNum, String cif, int turnoversValue) {
        return setTurnovers(accNum, cif, Collections.nCopies(12, turnoversValue).stream().mapToInt(i -> i).toArray());
    }

    public String setTurnovers(String accNum, String cif, int[] turnoversValues) {
        if (turnoversValues.length != 12) {
            throw new IllegalStateException("Array of turnovers doesn't have required length! Please enter values for all 12 months.");
        }

        FlxData flxData = new FlxData(false);
        flxData.setAccNum(accNum);
        flxData.setInstPtCif(cif);
        for (int i = 0; i < 12; i++) {
            flxData.setTurnoverForMonth(i, turnoversValues[i]);
        }

        ObjectTransferToServer data = new ObjectTransferToServer(IlodsServerAction.ODS_SET_TURNOVERS);
        data.addObject("FLX_BUS_DATA", flxData);

        ObjectTransferToClient response = sendRequest(data);
        FlxData respFlxData = (FlxData) response.getObject("FLX_BUS_DATA");
        String errorCode = respFlxData.getErrorCode();
        logger.info("Set turnovers result: " + (errorCode.equals("0") ? "OK" : "ERROR"));
        return errorCode;
    }

    public String setInfolimit(IlBusProdClass busProdClass, IlType ilType, IlSubType ilSubType, double ilAmount, IlApplTp applTpCode, String rcNum, String icoNum) {
        if (busProdClass.isClip() == true) {
            throw new HarnessException("Set infolimit CLIP is not implemented. Please contact Test Automation team.");
        }

        OdsEndpoint ods = (OdsEndpoint) store.getEndpoint(OdsEndpoint.class);
        long uniPtKey = ods.getUniPtKey(rcNum, icoNum);

        UniPtInfolimitData2 infolimitData = new UniPtInfolimitData2();
        infolimitData.setBusProdClassCode(busProdClass.getId());
        infolimitData.setInfolimitTpCode(ilType.getId());
        infolimitData.setInfolimitSubTpCode(ilSubType.getKey());
        infolimitData.setInfolimitAmt(ilAmount);
        infolimitData.setApplTpCode(applTpCode.toString());
        infolimitData.setUniPtKey(uniPtKey);

        infolimitData.normalizeData();

        ObjectTransferToServer data = new ObjectTransferToServer(IlodsServerAction.ODS_SET_INFOLIMIT);
        data.addObject("UNI_PT_INFOLIMIT_DATA", infolimitData);

        ObjectTransferToClient response = sendRequest(data);
        UniPtInfolimitData2 respUniPtInfolimitData = (UniPtInfolimitData2) response.getObject("UNI_PT_INFOLIMIT_DATA");
        String errorCode = respUniPtInfolimitData.getErrorCode();
        logger.info("Set infolimit result: " + (errorCode.equals("0") ? "OK" : "ERROR"));
        return errorCode;
    }

    public String setSegment(String segmentCode, String segmentationCode, String rcNum, String icoNum) {
        OdsEndpoint ods = (OdsEndpoint) store.getEndpoint(OdsEndpoint.class);
        String segmentKey = ods.checkSegmentCodeAndGetId(segmentCode, segmentationCode);
        if (segmentKey == null) {
            throw new IllegalStateException("The set segment (" + segmentCode + ") with segmentation (" + segmentationCode + ") doesn't exist!");
        }

        UniPtSegmData segmData = new UniPtSegmData();
        segmData.setSegmCode(segmentCode);
        segmData.setSegCode(segmentationCode);
        segmData.setSrcRole(segmentKey);

        segmData.setUniPtKey(ods.getUniPtKey(rcNum, icoNum));
        segmData.normalizeData();

        ObjectTransferToServer data = new ObjectTransferToServer(IlodsServerAction.ODS_SET_SEGMENT);
        data.addObject("UNI_PT_SEGM_DATA", segmData);

        ObjectTransferToClient response = sendRequest(data);
        UniPtSegmData respUniPtSegmData = (UniPtSegmData) response.getObject("UNI_PT_SEGM_DATA");
        String errorCode = respUniPtSegmData.getErrorCode();
        logger.info("Set segment result: " + (errorCode.equals("0") ? "OK" : "ERROR"));
        return errorCode;
    }

    public Map<String, Object> callMWF(String name, String version, TifClient tifClient, Map<String, Object> properties, Set<String> outputParamNames) {
        String xmlDefinition = "";
        try {
            try (InputStream xmlDefinitionFile = this.getClass()
                    .getClassLoader()
                    .getResourceAsStream("xmlMappings/" + tifClient.getTarget() + "_" + name + "_" + version + ".xml")) {
                try (InputStreamReader xmlDefinitionFileReader = new InputStreamReader(xmlDefinitionFile);
                     BufferedReader reader = new BufferedReader(xmlDefinitionFileReader)) {
                    xmlDefinition = reader.lines().collect(Collectors.joining(System.lineSeparator()));
                }
            }
        } catch (NullPointerException e) {
            throw new HarnessException("XML definition for " + name + "_" + version + " is not found");
        } catch (IOException e) {
            throw new HarnessException("XML definition for " + name + "_" + version + " is not readable");
        }

        ObjectTransferToServer data = new ObjectTransferToServer(IlodsServerAction.MWF);
        data.addObject("PARAMS", properties);
        data.addObject("OUT_PARAMS", outputParamNames);
        data.addObject("TIF_CLIENT", tifClient.toString());
        data.addObject("MWF_NAME", name);
        data.addObject("MWF_VERSION", version);
        data.addObject("MWF_DEFINITION", xmlDefinition);

        data.setRequestType(IlodsServerRequestType.MWF);
        ObjectTransferToClient response = sendRequest(data);

        return (Map<String, Object>) response.getObject("MQ_RESPONSE");
    }

    public static void sendEmail(String subject, String message) {
        ObjectTransferToServer data = new ObjectTransferToServer(IlodsServerAction.UTILS_SEND_MAIL);
        data.addObject("FROM_EMAIL", "ilods@moneta.cz");
        data.addObject("FROM_NAME", "ILODS (MONETA)");
        data.addObject("RECIPIENTS", new String[] { "vaclav.viktorin@moneta.cz" });
        data.addObject("SUBJECT", subject);
        data.addObject("MESSAGE_BODY", message);

        data.setRequestType(IlodsServerRequestType.WF);
        new IlodsServerConnector(IlodsServerEnvironmentList.XNA).sendRequest(data);
    }
}
