
package gov.va.med.cds.integration.vhim400;

import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertTrue;
import gov.va.med.cds.clinicaldata.DomainEntryPoint;
import gov.va.med.cds.integration.AbstractEndToEndOutpatientPharmacyTest;
import gov.va.med.cds.integration.AbstractEndToEndTest;
import gov.va.med.cds.junit.runners.BeforeTestsOnce;
import gov.va.med.cds.junit.runners.Suite;
import gov.va.med.cds.junit.runners.SuiteAwareSpringRunner;
import gov.va.med.cds.request.TemplateRequestProcessor;
import gov.va.med.cds.testharness.vhim400.TemplateIdHelper;
import gov.va.med.cds.testharness.vhim400.builders.BaseDatatypesBuilder;
import gov.va.med.cds.testharness.vhim400.builders.PathwaysDataBuilder;
import gov.va.med.cds.testharness.vhim400.builders.ClinicalDataBuilder;
import gov.va.med.cds.testharness.vhim400.builders.ClinicalDomainBuilderFactoryInterface;
import gov.va.med.cds.testharness.vhim400.builders.OutpatientMedicationPromiseBuilder;
import gov.va.med.cds.testharness.vhim400.builders.SensitivePatientDataAccessBuilder;
import gov.va.med.cds.testharness.vhim400.builders.SensitivePatientDataAccessBuilderFactory;

import gov.va.med.cds.uniqueidentifier.UniqueIdentifier;

import org.apache.commons.collections4.map.MultiValueMap;
import org.dom4j.Document;
import org.dom4j.DocumentHelper;
import org.dom4j.Element;
import org.dom4j.Node;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.core.JdbcTemplate;
import org.springframework.test.context.ContextConfiguration;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@RunWith(SuiteAwareSpringRunner.class)
@ContextConfiguration(locations = { "classpath:gov/va/med/cds/config/exceptionHandlingConfigContext.xml" })
public class EndToEndSensitivePatientAccessCreateTest extends AbstractEndToEndTest {

	protected static String PATIENTIDENTITY9 = "9";
	protected static String ASSIGNINGFACILITY1 = "578";
	protected static String DUZ1 = "545";

	protected static String PATIENTIDENTITY3 = "3";
	protected static String DUZ2 = "11249";

	protected static String MENUOPTION1 = "FTP APP";
	protected static String PATIENTIDENTITY5 = "5";

	protected static String ASSIGNINGFACILITY2 = "580";
	protected static String ASSIGNINGAUTHORITY = "USVHA";

	protected static String XPATH_PATIENT_DATA_ACCESS = "//patient/patientDataAccessedEvents/patientDataAccessedEvent";

	protected static final String DOMAINENTRYPOINT_XPATH = "//patientDataAccessedEvent";
	protected static final String REQUEST_ID_XPATH = "//requestId";
	protected static final String PATIENT_ID_XPATH = "//patientDataAccessedEvent/patient/identifier/identity";

	protected static final String ERROR_SECTION_XPATH = "//errorSection";
	protected static final String ERROR_SECTION_ERRORS_XPATH = "//logpatientaccesseddata:LogPatientAccessedData/errorSection/errors";
	protected static final String ERROR_SECTION_WARNINGS_XPATH = "//logpatientaccesseddata:LogPatientAccessedData/errorSection/warnings";
	protected static final String ERROR_SECTION_FATAL_ERRORS_XPATH = "//logpatientaccesseddata:LogPatientAccessedData/errorSection/fatalErrors";

	@Autowired
	protected JdbcTemplate hdrJdbcTemplate;
	@Autowired
	private TemplateRequestProcessor requestProcessor;

	@Test
	@Suite(groups = { "checkintest" })
	public void testSensitivePatientAccessSingleSiteCreate() throws Exception {

		String requestId = new UniqueIdentifier().toString();
		Document createRequestDoc = createWriteRequestXmlSingleSite(PATIENTIDENTITY9, ASSIGNINGFACILITY1, "545",
				"FTP APP", requestId);
		String createRequestXml = createRequestDoc.asXML();

		Document clinicalDataDocument = createAndAssertDomainData(
				TemplateIdHelper.SENSITIVE_PATIENT_ACCESS_CREATE1_TEMPLATE_ID, createRequestXml, requestId);

		checkForNoErrors(clinicalDataDocument);

		// Verify requestId
		String requestIdFromResponse = clinicalDataDocument.selectSingleNode(REQUEST_ID_XPATH).getText();
		assertTrue(requestId.equals(requestIdFromResponse));

	}

	@Test
	@Suite(groups = { "checkintest" })
	public void testSensitivePatientAccessMultiSitesCreate() throws Exception {

		String requestId = new UniqueIdentifier().toString();
		Document createRequestDoc = createWriteRequestXmlMultipleSites(PATIENTIDENTITY9, ASSIGNINGFACILITY1,
				ASSIGNINGFACILITY2, "545", "FTP APP", requestId);
		String createRequestXml = createRequestDoc.asXML();

		Document clinicalDataDocument = createAndAssertDomainData(
				TemplateIdHelper.SENSITIVE_PATIENT_ACCESS_CREATE1_TEMPLATE_ID, createRequestXml, requestId);

		checkForNoErrors(clinicalDataDocument);

		// Verify requestId
		String requestIdFromResponse = clinicalDataDocument.selectSingleNode(REQUEST_ID_XPATH).getText();
		assertTrue(requestId.equals(requestIdFromResponse));

	}

	@Test
	@Suite(groups = { "checkintest" })
	public void testSensitivePatientAccessNullDFNCreate() throws Exception {

		String requestId = new UniqueIdentifier().toString();
		Document createRequestDoc = createWriteRequestXmlNullDFN(PATIENTIDENTITY9, ASSIGNINGFACILITY1,
				ASSIGNINGFACILITY2, "545", "FTP APP", requestId);
		String createRequestXml = createRequestDoc.asXML();

		Document clinicalDataDocument = createAndAssertDomainData(
				TemplateIdHelper.SENSITIVE_PATIENT_ACCESS_CREATE1_TEMPLATE_ID, createRequestXml, requestId);

		checkForErrors(clinicalDataDocument);

		// Verify requestId
		String requestIdFromResponse = clinicalDataDocument.selectSingleNode(REQUEST_ID_XPATH).getText();
		assertTrue(requestId.equals(requestIdFromResponse));

	}

	private Document createWriteRequestXmlSingleSite(String pid, String facilityId, String duz, String menuOption,
			String requestId) {
		String clientRequestInitiationTime = "2016-06-06T12:01:01Z";
		PathwaysDataBuilder pathwaysDataBuilder = callBuilder();

		MultiValueMap<String, String> dfnDuzMap = new MultiValueMap<String, String>();

		dfnDuzMap.put(PATIENTIDENTITY9, DUZ1);

		dfnDuzMap.put(PATIENTIDENTITY5, DUZ2);

		dfnDuzMap.put(PATIENTIDENTITY5, DUZ1);

		Document vdmClinicalDataInsert = pathwaysDataBuilder.createClinicalData(
				TemplateIdHelper.SENSITIVE_PATIENT_ACCESS_CREATE1_TEMPLATE_ID, dfnDuzMap, facilityId, "FtP App", null,
				"FtP", clientRequestInitiationTime);

		return vdmClinicalDataInsert;
	}

	private Document createWriteRequestXmlMultipleSites(String pid, String facilityId1, String facilityId2, String duz,
			String menuOption, String requestId) {
		String clientRequestInitiationTime = "2016-06-06T12:01:01Z";
		PathwaysDataBuilder pathwaysDataBuilder = callBuilder();

		MultiValueMap<String, String> dfnDuzMap = new MultiValueMap<String, String>();

		dfnDuzMap.put(PATIENTIDENTITY9, DUZ1);

		dfnDuzMap.put(PATIENTIDENTITY5, DUZ2);

		dfnDuzMap.put(PATIENTIDENTITY5, DUZ1);

		Document vdmClinicalDataInsert = pathwaysDataBuilder.createClinicalData(
				TemplateIdHelper.SENSITIVE_PATIENT_ACCESS_CREATE1_TEMPLATE_ID, dfnDuzMap, facilityId1, facilityId2,
				"FtP App", null, "FtP", clientRequestInitiationTime);

		return vdmClinicalDataInsert;
	}

	private Document createWriteRequestXmlNullDFN(String pid, String facilityId1, String facilityId2, String duz,
			String menuOption, String requestId) {
		String clientRequestInitiationTime = "2016-06-06T12:01:01Z";
		PathwaysDataBuilder pathwaysDataBuilder = callBuilder();

		MultiValueMap<String, String> dfnDuzMap = new MultiValueMap<String, String>();

		dfnDuzMap.put(PATIENTIDENTITY9, DUZ1);
		dfnDuzMap.put("", DUZ1);

		Document vdmClinicalDataInsert = pathwaysDataBuilder.createClinicalData(
				TemplateIdHelper.SENSITIVE_PATIENT_ACCESS_CREATE1_TEMPLATE_ID, dfnDuzMap, facilityId1, facilityId2,
				"FtP App", null, "FtP", clientRequestInitiationTime);

		return vdmClinicalDataInsert;
	}

	private PathwaysDataBuilder callBuilder() {
		Map<String, DomainEntryPoint> domainEntryPointsMap = new HashMap<String, DomainEntryPoint>();
		domainEntryPointsMap.put(TemplateIdHelper.SENSITIVE_PATIENT_ACCESS_CREATE1_TEMPLATE_ID,
				DomainEntryPoint.PatientDataAccessedEvent);

		PathwaysDataBuilder pathwaysDataBuilder = new PathwaysDataBuilder("patient",
				"patient/patientDataAccessedEvents", "PathwaysResponse400", "logaccessdata", "Logaccessdata",
				"LogaccessData");
		pathwaysDataBuilder.setDomainEntryPointsMap(domainEntryPointsMap);

		Map<String, ClinicalDomainBuilderFactoryInterface> domainEntryPointsWrappersMap = new HashMap<String, ClinicalDomainBuilderFactoryInterface>();
		SensitivePatientDataAccessBuilderFactory factory = new SensitivePatientDataAccessBuilderFactory();
		factory.setSensitivePatientDataAccessBuilder(new SensitivePatientDataAccessBuilder());
		domainEntryPointsWrappersMap.put("PatientDataAccessedEvent", factory);
		pathwaysDataBuilder.setDomainEntryPointsWrappersMap(domainEntryPointsWrappersMap);
		return pathwaysDataBuilder;
	}

	@SuppressWarnings("unchecked")
	protected Document createAndAssertDomainData(String templateId, String createRequestXml, String requestId)
			throws Exception {

		Document clinicalDataDocument = requestProcessor.createClinicalData(createRequestXml, templateId, requestId);
		assertNotNull(clinicalDataDocument);

		return clinicalDataDocument;
	}

	private void checkForNoErrors(Document clinicalDataDocument) {
		
		// Check for an empty error section
		List<Element> errorSections = clinicalDataDocument.selectNodes(ERROR_SECTION_XPATH);
		assertTrue(errorSections.size() == 0);
	}

	private void checkForErrors(Document clinicalDataDocument) {

		List<Element> fatalErrors = clinicalDataDocument.selectNodes(ERROR_SECTION_FATAL_ERRORS_XPATH);
		assertTrue(fatalErrors.size() == 1);
	}

}
