package be.ehealth.businessconnector.hubv3.session;

import be.ehealth.business.common.domain.Patient;
import be.ehealth.business.intrahubcommons.exception.IntraHubBusinessConnectorException;
import be.ehealth.business.kmehrcommons.helper.ErrorTypeManagement;
import be.ehealth.businessconnector.hubv3.helpers.HubConfigCommon;
import be.ehealth.businessconnector.hubv3.helpers.HubConfigRsw;
import be.ehealth.businessconnector.hubv3.helpers.HubTestHelper;
import be.ehealth.businessconnector.testcommons.BusinessSessionRule;
import be.ehealth.technicalconnector.exception.TechnicalConnectorException;
import be.ehealth.technicalconnector.utils.ConnectorXmlUtils;
import be.fgov.ehealth.hubservices.core.v3.AccessRightType;
import be.fgov.ehealth.hubservices.core.v3.ConsentHCPartyType;
import be.fgov.ehealth.hubservices.core.v3.ConsentType;
import be.fgov.ehealth.hubservices.core.v3.FolderType;
import be.fgov.ehealth.hubservices.core.v3.GetHCPartyConsentResponse;
import be.fgov.ehealth.hubservices.core.v3.GetHCPartyResponse;
import be.fgov.ehealth.hubservices.core.v3.GetLatestUpdateResponse;
import be.fgov.ehealth.hubservices.core.v3.GetPatientConsentResponse;
import be.fgov.ehealth.hubservices.core.v3.GetPatientResponse;
import be.fgov.ehealth.hubservices.core.v3.GetTherapeuticLinkResponse;
import be.fgov.ehealth.hubservices.core.v3.GetTransactionListResponse;
import be.fgov.ehealth.hubservices.core.v3.GetTransactionResponse;
import be.fgov.ehealth.hubservices.core.v3.GetTransactionSetResponse;
import be.fgov.ehealth.hubservices.core.v3.HCPartyIdType;
import be.fgov.ehealth.hubservices.core.v3.HcpartyType;
import be.fgov.ehealth.hubservices.core.v3.KmehrHeaderDeclareTransaction;
import be.fgov.ehealth.hubservices.core.v3.LocalSearchType;
import be.fgov.ehealth.hubservices.core.v3.PatientIdType;
import be.fgov.ehealth.hubservices.core.v3.PutHCPartyConsentResponse;
import be.fgov.ehealth.hubservices.core.v3.PutHCPartyResponse;
import be.fgov.ehealth.hubservices.core.v3.PutPatientConsentResponse;
import be.fgov.ehealth.hubservices.core.v3.PutPatientResponse;
import be.fgov.ehealth.hubservices.core.v3.PutTherapeuticLinkResponse;
import be.fgov.ehealth.hubservices.core.v3.PutTransactionResponse;
import be.fgov.ehealth.hubservices.core.v3.PutTransactionSetResponse;
import be.fgov.ehealth.hubservices.core.v3.RevokeHCPartyConsentResponse;
import be.fgov.ehealth.hubservices.core.v3.RevokePatientConsentResponse;
import be.fgov.ehealth.hubservices.core.v3.RevokeTherapeuticLinkResponse;
import be.fgov.ehealth.hubservices.core.v3.RevokeTransactionResponse;
import be.fgov.ehealth.hubservices.core.v3.SelectRevokeAccessRightType;
import be.fgov.ehealth.hubservices.core.v3.TherapeuticLinkType;
import be.fgov.ehealth.hubservices.core.v3.TransactionIdType;
import be.fgov.ehealth.hubservices.core.v3.TransactionSummaryType;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDACCESSRIGHT;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDACCESSRIGHTschemes;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDACCESSRIGHTvalues;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDTRANSACTION;
import be.fgov.ehealth.standards.kmehr.cd.v1.CDTRANSACTIONschemes;
import be.fgov.ehealth.standards.kmehr.id.v1.IDKMEHR;
import be.fgov.ehealth.standards.kmehr.id.v1.IDKMEHRschemes;
import be.fgov.ehealth.standards.kmehr.schema.v1.AuthorType;
import be.fgov.ehealth.standards.kmehr.schema.v1.ErrorType;
import be.fgov.ehealth.standards.kmehr.schema.v1.Kmehrmessage;
import be.fgov.ehealth.standards.kmehr.schema.v1.PersonType;
import be.fgov.ehealth.technicalconnector.tests.utils.XmlAsserter;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.joda.time.DateTime;
import org.junit.ClassRule;
import org.junit.FixMethodOrder;
import org.junit.Ignore;
import org.junit.Rule;
import org.junit.Test;
import org.junit.rules.ExpectedException;
import org.junit.rules.TestRule;
import org.junit.runners.MethodSorters;

import java.util.List;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;

@FixMethodOrder(MethodSorters.NAME_ASCENDING)
public class WalkThroughRswIntegrationTest {

    @ClassRule
    public static TestRule sessionPrerequisite = BusinessSessionRule.withActiveSession("/be.ehealth.businessconnector.intrahubv3.test.properties");

    @ClassRule
    public static InitRswHubRule hubPrerequesite = new InitRswHubRule();

    @Rule
    public ExpectedException expectedException = ExpectedException.none();

    /**
     * SL for medication scheme transaction identification (platform-dependant)
     */
    private static final String URI_TRANSACTION = "RSWID";

    private static String transactionId;

    private static String transactionSetId;


    private static int latestMedicationSchemeVersion;

    private final HubService hubService = hubPrerequesite.getHubService();

    private HubTestHelper helper = new HubTestHelper("rsw", new Patient.Builder().withFirstName(HubConfigRsw.PATIENT_FIRSTNAME).withFamilyName(HubConfigRsw.PATIENT_LASTNAME).withInss(HubConfigRsw.PATIENT_NISS).build());


    @Test
    public void _010_putHcPartyConsent() throws Exception {
        ConsentHCPartyType consent = new ConsentHCPartyType();
        consent.setAuthor(helper.createAuthor());
        consent.setHcparty(helper.createHcPartyIdProfessional());
        consent.setSigndate(new DateTime());
        PutHCPartyConsentResponse putHCPartyConsent = hubService.putHCPartyConsent(consent);

        List<ErrorType> errors = putHCPartyConsent.getAcknowledge().getErrors();
        assertTrue(ErrorTypeManagement.printErrors(errors), errors.isEmpty() || StringUtils.contains(errors.get(0).getCds().get(0).getValue(), "PERHCP.CONSENT.EXISTS"));
    }

    @Test
    public void _020_putPatient() throws Exception {
        PersonType person = helper.createPatient();
        PutPatientResponse putPatientResponse = hubService.putPatient(person);

        XmlAsserter.assertSimilar(helper.expectedResponse("PutPatient"), ConnectorXmlUtils.toString(putPatientResponse));
    }

    @Test
    public void _030_getPatient() throws IntraHubBusinessConnectorException, TechnicalConnectorException {
        GetPatientResponse getPatientResponse = hubService.getPatient(helper.createPatientIdType());

        XmlAsserter.assertSimilar(helper.expectedResponse("GetPatient"), ConnectorXmlUtils.toString(getPatientResponse));
    }

    @Test
    public void _040_putPatientConsent() throws Exception {
        PutPatientConsentResponse putPatientConsent = hubService.putPatientConsent(helper.createConsentType());

        XmlAsserter.assertSimilar(helper.expectedResponse("PutPatientConsent"), ConnectorXmlUtils.toString(putPatientConsent));
    }

    @Test
    public void _050_putTherapeuticLink() throws Exception {
        TherapeuticLinkType therapeuticLink = helper.createTherapeuticLinkType();
        PutTherapeuticLinkResponse putTherapeuticLinkResponse = hubService.putTherapeuticLink(therapeuticLink);

        XmlAsserter.assertSimilar(helper.expectedResponse("PutTherapeuticLink"), ConnectorXmlUtils.toString(putTherapeuticLinkResponse));
    }

    @Test
    public void _060_putTransaction() throws Exception {
        Kmehrmessage kmehrmessage = helper.createPutTransactionMessageWithLocalId();
        PutTransactionResponse putTransaction = hubService.putTransaction(kmehrmessage);

        // Retrieve the local id for later use
        List<IDKMEHR> idkmehrs = putTransaction.getTransaction().getIds();
        transactionId = retrieveLocalId(idkmehrs);

        XmlAsserter.assertSimilar(helper.expectedResponse("PutTransaction"), ConnectorXmlUtils.toString(putTransaction));
    }

    private String retrieveLocalId(List<IDKMEHR> idkmehrs) {
        for (IDKMEHR idkmehr : idkmehrs) {
            if (IDKMEHRschemes.LOCAL.equals(idkmehr.getS())) {
                return  idkmehr.getValue();
            }
        }
        return null;
    }

    @Test
    public void _070_getPatientConsent() throws TechnicalConnectorException, IntraHubBusinessConnectorException {
        GetPatientConsentResponse patientConsentResponse = hubService.getPatientConsent(helper.createSelectGetPatientConsentType());

        XmlAsserter.assertSimilar(helper.expectedResponse("GetPatientConsent"), ConnectorXmlUtils.toString(patientConsentResponse));
    }

    @Test
    public void _080_getTherapeuticLink() throws Exception {
        GetTherapeuticLinkResponse getTherapeuticLinkResponse = hubService.getTherapeuticLink(helper.createSelectGetHCPartyPatientConsentType());

        XmlAsserter.assertSimilar(helper.expectedResponse("GetTherapeuticLink"), ConnectorXmlUtils.toString(getTherapeuticLinkResponse));
    }

    @Test
    public void _090_getTransactionList() throws Exception {
        PatientIdType patientId = helper.createPatientIdType();
        GetTransactionListResponse transactionListResponse = hubService.getTransactionList(patientId, LocalSearchType.GLOBAL, helper.createTransactionWithPeriodType());

        assertNotNull("Kmehrheader should be present", transactionListResponse.getKmehrheader());
        assertTrue("Transaction list should not be empty", CollectionUtils.isNotEmpty(transactionListResponse.getKmehrheader().getFolder().getTransactions()));

        // retrieve a medicationscheme for later use
        for (TransactionSummaryType transactionSummaryType : transactionListResponse.getKmehrheader().getFolder().getTransactions()) {
            for (CDTRANSACTION cdtransaction : transactionSummaryType.getCds()) {
                if (CDTRANSACTIONschemes.CD_HUBSERVICE.equals(cdtransaction.getS()) && "gettransactionset".equals(cdtransaction.getValue())) {
                    for (IDKMEHR idkmehr : transactionSummaryType.getIds()) {
                        if (IDKMEHRschemes.LOCAL.equals(idkmehr.getS())) {
                            transactionSetId = idkmehr.getValue();
                            break;
                        }
                    }
                }
            }
        }
    }

    @Test
    public void _100_getTransaction() throws Exception {
        PatientIdType patientId = helper.createPatientIdType();
        GetTransactionResponse transactionResponse = hubService.getTransaction(patientId, helper.createTransactionBaseType("RSWID", transactionId));

        XmlAsserter.assertSimilar(helper.expectedResponse("GetTransaction"), ConnectorXmlUtils.toString(transactionResponse));
    }

    @Test
    public void _110_revokeTransaction() throws Exception {
        RevokeTransactionResponse revokeTransactionResponse = hubService.revokeTransaction(helper.createPatientIdType(), helper.createTransactionBaseType(URI_TRANSACTION, transactionId));

        XmlAsserter.assertSimilar(helper.expectedResponse("RevokeTransaction"), ConnectorXmlUtils.toString(revokeTransactionResponse));
    }

    @Test
    public void _120_getLastestUpdate() throws Exception {
        GetLatestUpdateResponse latestUpdateResponse = hubService.getLatestUpdate(helper.createSelectGetLatestUpdateType());
        latestMedicationSchemeVersion = helper.getLatestMedicationSchemeVersion(latestUpdateResponse);

        XmlAsserter.assertSimilar(helper.expectedResponse("GetLatestUpdate"), ConnectorXmlUtils.toString(latestUpdateResponse));
    }

    @Test
    public void _130_putTransactionSet() throws Exception {
        Kmehrmessage kmehrmessage = helper.createTransactionSetMessage(latestMedicationSchemeVersion, transactionSetId);

        PutTransactionSetResponse putTransactionSetResponse = hubService.putTransactionSet(kmehrmessage);

        XmlAsserter.assertSimilar(helper.expectedResponse("PutTransactionSet"), ConnectorXmlUtils.toString(putTransactionSetResponse));
    }

    @Test
    public void _140_getTransactionSet() throws Exception {
        PatientIdType patientId = helper.createPatientIdType();

        GetTransactionSetResponse transactionSetResponse = hubService.getTransactionSet(patientId, helper.createTransactionBaseType(URI_TRANSACTION, transactionSetId));

        XmlAsserter.assertSimilar(helper.expectedResponse("GetTransactionSet"), ConnectorXmlUtils.toString(transactionSetResponse));
    }


    @Test
    @Ignore("Not implemented by RSW")
    public void _150_declareTransaction() throws Exception {
        KmehrHeaderDeclareTransaction kmehrHeader = new KmehrHeaderDeclareTransaction();
        FolderType folder = new FolderType();
        PatientIdType patient = helper.createPatientIdType();

        TransactionSummaryType transaction = new TransactionSummaryType();
        AuthorType author = helper.createAuthor();
        transaction.setAuthor(author);
        CDTRANSACTION cdTransaction = new CDTRANSACTION();
        cdTransaction.setS(CDTRANSACTIONschemes.CD_TRANSACTION);
        cdTransaction.setSV("1.0");
        cdTransaction.setValue("sumehr");
        transaction.getCds().add(cdTransaction);
        transaction.setDate(new DateTime());
        transaction.getIds().add(helper.createMessageId(HubConfigCommon.MESSAGE_ID));
        transaction.setIscomplete(true);
        transaction.setIsvalidated(true);
        transaction.setTime(new DateTime());
        transaction.setRecorddatetime(new DateTime());

        folder.setTransaction(transaction);
        folder.setPatient(patient);
        kmehrHeader.setFolder(folder);
        hubService.declareTransaction(kmehrHeader);
    }

    @Test
    @Ignore("Not implemented by RSW")
    public void _170_requestPublication() throws IntraHubBusinessConnectorException, TechnicalConnectorException {
        hubService.requestPublication(helper.createPatientIdType(), helper.createTransactionWithPeriodType(), "");
    }

    @Test
    public void _180_putHcParty() throws TechnicalConnectorException, IntraHubBusinessConnectorException {
        PutHCPartyResponse putHCPartyResponse = hubService.putHCParty(helper.createHcPartyAdaptedType());

        XmlAsserter.assertSimilar(helper.expectedResponse("PutHcParty"), ConnectorXmlUtils.toString(putHCPartyResponse));

    }

    @Test
    public void _190_getHcParty() throws TechnicalConnectorException, IntraHubBusinessConnectorException {
        HCPartyIdType hcParty = helper.createHcPartyIdProfessional();
        GetHCPartyResponse getHCPartyResponse = hubService.getHCParty(hcParty);

        XmlAsserter.assertSimilar(helper.expectedResponse("GetHcParty"), ConnectorXmlUtils.toString(getHCPartyResponse));
    }

    @Test
    public void _200_getHcPartyConsent() throws TechnicalConnectorException, IntraHubBusinessConnectorException {
        HCPartyIdType hcParty = helper.createHcPartyIdProfessional();
        GetHCPartyConsentResponse getHCPartyConsentResponse = hubService.getHCPartyConsent(hcParty);

        XmlAsserter.assertSimilar(helper.expectedResponse("GetHcPartyConsent"), ConnectorXmlUtils.toString(getHCPartyConsentResponse));
    }

    @Test
    public void _210_revokeHcPartyConsent() throws TechnicalConnectorException, IntraHubBusinessConnectorException {
        ConsentHCPartyType consent = new ConsentHCPartyType();
        consent.setAuthor(helper.createAuthor());
        consent.setHcparty(helper.createHcPartyIdProfessional());
        consent.setRevokedate(new DateTime());
        consent.setSigndate(new DateTime());

        RevokeHCPartyConsentResponse revokePatientConsentResponse = hubService.revokeHCPartyConsent(consent);

        XmlAsserter.assertSimilar(helper.expectedResponse("RevokeHcPartyConsent"), ConnectorXmlUtils.toString(revokePatientConsentResponse));
    }

    @Test
    public void _220_revokeTherapeuticLink() throws Exception {
        TherapeuticLinkType therapeuticLink = helper.createTherapeuticLinkType();
        therapeuticLink.setEnddate(new DateTime());
        RevokeTherapeuticLinkResponse revokeTherapeuticLinkResponse = hubService.revokeTherapeuticLink(therapeuticLink);

        XmlAsserter.assertSimilar(helper.expectedResponse("RevokeTherapeuticLink"), ConnectorXmlUtils.toString(revokeTherapeuticLinkResponse));
    }

    @Test
    public void _230_revokePatientConsent() throws Exception {
        ConsentType consent = helper.createConsentType();
        consent.setRevokedate(new DateTime());
        RevokePatientConsentResponse revokePatientConsentResponse = hubService.revokePatientConsent(consent);

        XmlAsserter.assertSimilar(helper.expectedResponse("RevokePatientConsent"), ConnectorXmlUtils.toString(revokePatientConsentResponse));
    }

    @Test
    @Ignore("Not implemented by RSW")
    public void _240_putAccessRight() throws TechnicalConnectorException, IntraHubBusinessConnectorException {
        AccessRightType accessRight = new AccessRightType();
        CDACCESSRIGHT cdAccessRight = new CDACCESSRIGHT();
        cdAccessRight.setS(CDACCESSRIGHTschemes.CD_ACCESSRIGHT);
        cdAccessRight.setSV("1.0");
        cdAccessRight.setValue(CDACCESSRIGHTvalues.ALLOW);
        accessRight.setCd(cdAccessRight);
        be.fgov.ehealth.hubservices.core.v3.HcpartyType hcParty = new be.fgov.ehealth.hubservices.core.v3.HcpartyType();
        hcParty.getCds().add(helper.createCdHcPartyProfession());
        hcParty.getIds().add(helper.createIdHcPartyNihii());
        accessRight.setHcparty(hcParty);
        TransactionIdType transaction = helper.createTransactionIdType(transactionId);
        accessRight.setTransaction(transaction);
        hubService.putAccessRight(accessRight);
    }

    @Test
    @Ignore("Not implemented by RSW")
    public void _250_getAccessRight() throws IntraHubBusinessConnectorException, TechnicalConnectorException {
        TransactionIdType transaction = new TransactionIdType();
        IDKMEHR id = helper.createMessageId(HubConfigCommon.MESSAGE_ID);
        transaction.getIds().add(id);
        hubService.getAccessRight(transaction);
    }

    @Test
    @Ignore("Not implemented by RSW")
    public void _260_revokeAccessRight() throws IntraHubBusinessConnectorException, TechnicalConnectorException {
        SelectRevokeAccessRightType accessRight = new SelectRevokeAccessRightType();
        HcpartyType hcParty = new HcpartyType();
        hcParty.getCds().add(helper.createCdHcPartyProfession());
        hcParty.getIds().add(helper.createIdHcPartyNihii());
        accessRight.setHcparty(hcParty);
        accessRight.setTransaction(helper.createTransactionIdType(transactionId));
        hubService.revokeAccessRight(accessRight);
    }

   
}
