/*
 * Copyright (c) eHealth
 */
package be.ehealth.businessconnector.dmg.util;

import java.security.NoSuchAlgorithmException;
import java.util.List;
import java.util.Map;
import java.util.zip.DataFormatException;

import org.apache.commons.lang.StringUtils;
import org.joda.time.DateTime;
import org.junit.Assert;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import be.cin.nip.async.generic.MsgResponse;
import be.cin.nip.async.generic.Responses;
import be.cin.nip.async.generic.TAck;
import be.cin.nip.async.generic.TAckResponse;
import be.ehealth.business.common.domain.Patient;
import be.ehealth.business.mycarenetcommons.helper.ErrorMyCarenetTypeManagement;
import be.ehealth.businessconnector.dmg.builders.ResponseObjectBuilder;
import be.ehealth.businessconnector.dmg.builders.ResponseObjectBuilderFactory;
import be.ehealth.businessconnector.dmg.domain.DMGReferences;
import be.ehealth.businessconnector.dmg.domain.DmgBuilderResponse;
import be.ehealth.technicalconnector.exception.TechnicalConnectorException;
import be.ehealth.technicalconnector.idgenerator.IdGeneratorFactory;
import be.ehealth.technicalconnector.utils.ConnectorIOUtils;
import be.ehealth.technicalconnector.utils.MarshallerHelper;
import be.fgov.ehealth.globalmedicalfile.protocol.v1.SendResponseType;
import be.fgov.ehealth.messageservices.core.v1.AcknowledgeType;
import be.fgov.ehealth.messageservices.core.v1.SendTransactionResponse;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDCONTENT;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDCONTENTschemes;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDERRORMYCARENET;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDSEX;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDSEXvalues;
import be.fgov.ehealth.standards.kmehr.id.v1.IDINSURANCE;
import be.fgov.ehealth.standards.kmehr.id.v1.IDPATIENT;
import be.fgov.ehealth.standards.kmehr.id.v1.IDPATIENTschemes;
import be.fgov.ehealth.standards.kmehr.schema.v1.AuthorType;
import be.fgov.ehealth.standards.kmehr.schema.v1.ErrorMyCarenetType;
import be.fgov.ehealth.standards.kmehr.schema.v1.HcpartyType;
import be.fgov.ehealth.standards.kmehr.schema.v1.HeaderType;
import be.fgov.ehealth.standards.kmehr.schema.v1.Kmehrmessage;
import be.fgov.ehealth.standards.kmehr.schema.v1.MemberinsuranceType;
import be.fgov.ehealth.standards.kmehr.schema.v1.PersonType;
import be.fgov.ehealth.standards.kmehr.schema.v1.SexType;
import be.fgov.ehealth.technicalconnector.signature.domain.SignatureVerificationResult;


/**
 * some test utility methods for DMG tests.
 * 
 * @author EHP
 * 
 */
public final class DmgTestUtils {


    private static final Logger LOG = LoggerFactory.getLogger(DmgTestUtils.class);

    /**
     * no need for an instance.
     */
    private DmgTestUtils() {
        super();
    }

    /**
     * @return
     * @throws TechnicalConnectorException
     */
    public static DMGReferences createDmgReferenceForTest() throws TechnicalConnectorException {
        String inputReference = IdGeneratorFactory.getIdGenerator().generateId();
        inputReference = "T" + inputReference.substring(1);
        DMGReferences references = new DMGReferences(inputReference);
        return references;
    }

    public static String logTackResponse(TAckResponse tackResponse) {
        StringBuilder sb = new StringBuilder();
        sb.append("tackResponse : ");
        if (tackResponse != null) {
            sb.append("xades T : ").append(tackResponse.getXadesT() != null ? "true" : "false");
            TAck tack = tackResponse.getTAck();
            sb.append("major : ").append(tack.getResultMajor());
            sb.append(", minor : ").append(tack.getResultMinor());
            sb.append(", message : ").append(tack.getResultMessage());
            sb.append(", id : ").append(tack.getId());
            sb.append(", applies to : ").append(tack.getAppliesTo());
            sb.append(", issuer : ").append(tack.getIssuer());
            sb.append(", value : ").append(tack.getValue());
        } else {
            sb.append("null");
        }
        return sb.toString();
    }

    /**
     * @param responseReturn
     * @throws TechnicalConnectorException
     */
    public static void logGetResponse(Responses responseReturn) throws TechnicalConnectorException {
        LOG.debug("MSG RESPONSE : " + responseReturn.getMsgCount() + " ------------------------------------------------------------------------------------------");
        for (MsgResponse msgResponse : responseReturn.getMsgResponses()) {
            LOG.debug("---------------------------------------------------------------------------------------------------------");
            DmgBuilderResponse response = ResponseObjectBuilderFactory.getResponseObjectBuilder().handleAsyncResponse(msgResponse);
            LOG.debug("content:" + new String(response.getResponse()));
        }
        LOG.debug("TACK RESPONSE : " + responseReturn.getTAckCount() + " ------------------------------------------------------------------------------------------");
        for (TAckResponse tackResponse : responseReturn.getTAckResponses()) {
            LOG.debug("tack : xades = " + (tackResponse.getXadesT() == null) + "  id : " + tackResponse.getTAck().getId());
            LOG.debug(logTackResponse(tackResponse));
            LOG.debug("---------------------------------------------------------------------------------------------------------");
        }
        LOG.debug("---------------------------------------------------------------------------------------------------");
    }

    /**
     * @param firstName
     * @param lastName
     * @param mutualityNumber
     * @param inss
     * @return
     */
    public static Patient createPatient(String firstName, String lastName, int mutualityNumber, long inss) {
        Patient pI = new Patient();
        pI.setFirstName(firstName);
        pI.setLastName(lastName);
        pI.setMutuality(formatToInszNumber(Integer.toString(mutualityNumber)));
        pI.setInss(formatToInszNumber(Long.toString(inss)));
        return pI;
    }

    /**
     * @param inss
     * @return
     */
    private static String formatToInszNumber(String numberString) {
        if (numberString.length() >= 1 && numberString.length() < 11) {
            numberString = StringUtils.leftPad(numberString, 11, '0');
        }
        return numberString;
    }

    /**
     * @param nomenclature
     * @param request
     */
    public static void replaceNomenclatureCodeInRequest(String nomenclature, Kmehrmessage request) {
        request.getFolders().get(0).getTransactions().get(0).getItem().get(2).getContents().get(0).getCds().clear();
        CDCONTENT cdcontent = new CDCONTENT();
        cdcontent.setS(CDCONTENTschemes.CD_NIHDI);
        cdcontent.setSV("1.0");
        cdcontent.setValue(nomenclature);
        request.getFolders().get(0).getTransactions().get(0).getItem().get(2).getContents().get(0).getCds().add(cdcontent);
    }

    /**
     * @param dmgEncounterDate
     * @param request
     */
    public static void replaceEncounterDateInRequest(DateTime dmgEncounterDate, Kmehrmessage request) {
        request.getFolders().get(0).getTransactions().get(0).getItem().get(1).getContents().get(0).setDate(dmgEncounterDate);
    }

    /**
     * @param request
     * @param dmgTarget
     */
    public static void replaceDmgTargetInRequest(Kmehrmessage request, HcpartyType dmgTarget) {
        request.getFolders().get(0).getTransactions().get(0).getItem().get(0).getContents().get(0).setHcparty(dmgTarget);
    }

    /**
     * @param request
     * @param senderHcParties
     */
    public static void replaceSenderInRequest(Kmehrmessage request, List<HcpartyType> senderHcParties) {
        HeaderType header = request.getHeader();
        header.getSender().getHcparties().clear();
        header.getSender().getHcparties().addAll(senderHcParties);
    }

    /**
     * @param request
     * @param author
     */
    public static void replaceAuthorInFirstFolder(Kmehrmessage request, AuthorType author) {
        request.getFolders().get(0).getTransactions().get(0).getAuthor().getHcparties().clear();
        request.getFolders().get(0).getTransactions().get(0).setAuthor(author);
    }

    /**
     * @param pI
     * @param sex
     * @param request
     */
    public static void replacePatientInFirstFolder(Patient pI, String sex, Kmehrmessage request) {
        PersonType patient = new PersonType();
        IDPATIENT idpatient = new IDPATIENT();
        idpatient.setSV("1.0");
        idpatient.setValue(pI.getInss());
        idpatient.setS(IDPATIENTschemes.ID_PATIENT);
        patient.getIds().add(idpatient);
    
        if (sex != null && !sex.isEmpty()) {
            CDSEX cdsex = new CDSEX();
            cdsex.setSV("1.0");
            cdsex.setS("CD-SEX");
            cdsex.setValue(CDSEXvalues.fromValue(sex));
            SexType sexType = new SexType();
            sexType.setCd(cdsex);
            patient.setSex(sexType);
        }
        MemberinsuranceType member = new MemberinsuranceType();
    
        if (pI.getRegNrWithMut() != null) {
            member.setMembership(pI.getRegNrWithMut());
            if (pI.getMutuality() != null) {
                IDINSURANCE id = new IDINSURANCE();
                id.setSV("1.0");
                id.setValue(pI.getMutuality());
                member.setId(id);
            }
        }
        if (member.getId() != null || member.getMembership() != null) {
            patient.setInsurancymembership(member);
        }
        patient.setFamilyname(pI.getLastName());
        patient.getFirstnames().add(pI.getFirstName());
    
    
        request.getFolders().get(0).setPatient(patient);
    }

    /**
     * @return
     * @throws TechnicalConnectorException
     */
    public static Kmehrmessage getFilledSendTransactionRequestFromXmlFile() throws TechnicalConnectorException {
        byte[] expected = ConnectorIOUtils.getBytes(ConnectorIOUtils.getResourceAsStream("/templates/SendTransactionRequest.kmerhmessage.xml"));
    
        MarshallerHelper<Kmehrmessage, Kmehrmessage> kmehrRequestMarshaller = new MarshallerHelper<Kmehrmessage, Kmehrmessage>(Kmehrmessage.class, Kmehrmessage.class);
        Kmehrmessage request = kmehrRequestMarshaller.toObject(expected);
        return request;
    }

    /**
     * @param resp
     * @throws TechnicalConnectorException
     * @throws NoSuchAlgorithmException
     * @throws DataFormatException
     */
    public static void validateSendResponseType(SendResponseType resp) throws TechnicalConnectorException, NoSuchAlgorithmException, DataFormatException {
        ResponseObjectBuilder respBuilder = ResponseObjectBuilderFactory.getResponseObjectBuilder();
        DmgBuilderResponse response = respBuilder.handleSendResponseType(resp);
    
        Assert.assertEquals("Status code not 200", "200", response.getEhealthStatus());
    
        SendTransactionResponse sendTransactionResponse = response.getSendTransactionResponse();
        Assert.assertNotNull(sendTransactionResponse);
        AcknowledgeType acknowledge = sendTransactionResponse.getAcknowledge();
        Assert.assertNotNull(acknowledge);
    
        List<ErrorMyCarenetType> errors = acknowledge.getErrors();
        boolean alreadyExists = checkIfDmgAlreadyExists(errors);
        if (!alreadyExists) {
            Assert.assertNotNull("kmehrMessage empty: errors:" + ErrorMyCarenetTypeManagement.printErrors(errors), sendTransactionResponse.getKmehrmessage());
        }
    
        Map<String, Object> resultMap = response.getResult();
        Assert.assertNotNull(resultMap.get(DmgBuilderResponse.RESULT_AS_BYTE));
        Assert.assertNotNull(resultMap.get(DmgBuilderResponse.RESULT_EHEALTH_STATUS));
        Assert.assertNotNull(resultMap.get(DmgBuilderResponse.RESULT_HAS_SIGNATURE));
        Assert.assertNotNull(resultMap.get(DmgBuilderResponse.RESULT_ORGINAL));
        Assert.assertNotNull(resultMap.get(DmgBuilderResponse.RESULT_SIGINATURE_VERIFICATION));
        Assert.assertEquals("200", resultMap.get(DmgBuilderResponse.RESULT_EHEALTH_STATUS));
        Assert.assertEquals(true, resultMap.get(DmgBuilderResponse.RESULT_HAS_SIGNATURE));
    
        SignatureVerificationResult verificationResult = (SignatureVerificationResult) resultMap.get(DmgBuilderResponse.RESULT_SIGINATURE_VERIFICATION);
        Assert.assertEquals(true, verificationResult.isValid());
    }

    /**
     * @param errors
     */
    private static boolean checkIfDmgAlreadyExists(List<ErrorMyCarenetType> errors) {
        if (errors != null && !errors.isEmpty()) {
            for (ErrorMyCarenetType error : errors) {
                CDERRORMYCARENET cderrormycarenet = error.getCds().get(0);
                Assert.assertTrue("checking if dmg already exists : expecting 161 or 165 but was" + cderrormycarenet.getValue(), cderrormycarenet.getValue().equals("161") || cderrormycarenet.getValue().equals("165"));
            }
            return true;
        }
        return false;
    }


}
