package ca.uhn.fhir.jpa.dao.r4;

import ca.uhn.fhir.jpa.api.config.DaoConfig;
import ca.uhn.fhir.rest.server.exceptions.InvalidRequestException;
import ca.uhn.fhir.rest.server.exceptions.ResourceVersionConflictException;
import ca.uhn.fhir.util.TestUtil;
import org.hl7.fhir.instance.model.api.IIdType;
import org.hl7.fhir.r4.model.Organization;
import org.hl7.fhir.r4.model.Patient;
import org.hl7.fhir.r4.model.Reference;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.Test;

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.fail;

public class FhirResourceDaoR4ReferentialIntegrityTest extends BaseJpaR4Test {

	@AfterEach
	public void afterResetConfig() {
		myDaoConfig.setEnforceReferentialIntegrityOnWrite(new DaoConfig().isEnforceReferentialIntegrityOnWrite());
		myDaoConfig.setEnforceReferentialIntegrityOnDelete(new DaoConfig().isEnforceReferentialIntegrityOnDelete());
	}

	@Test
	public void testCreateUnknownReferenceFail() throws Exception {

		Patient p = new Patient();
		p.setManagingOrganization(new Reference("Organization/AAA"));
		try {
			myPatientDao.create(p);
			fail();
		} catch (InvalidRequestException e) {
			assertEquals("Resource Organization/AAA not found, specified in path: Patient.managingOrganization", e.getMessage());
		}

	}

	@Test
	public void testCreateUnknownReferenceAllow() throws Exception {
		myDaoConfig.setEnforceReferentialIntegrityOnWrite(false);

		Patient p = new Patient();
		p.setManagingOrganization(new Reference("Organization/AAA"));
		IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless();

		p = myPatientDao.read(id);
		assertEquals("Organization/AAA", p.getManagingOrganization().getReference());

	}

	@Test
	public void testDeleteFail() throws Exception {
		Organization o = new Organization();
		o.setName("FOO");
		IIdType oid = myOrganizationDao.create(o).getId().toUnqualifiedVersionless();

		Patient p = new Patient();
		p.setManagingOrganization(new Reference(oid));
		IIdType pid = myPatientDao.create(p).getId().toUnqualifiedVersionless();

		try {
			myOrganizationDao.delete(oid);
			fail();
		} catch (ResourceVersionConflictException e) {
			assertEquals("Unable to delete Organization/"+oid.getIdPart()+" because at least one resource has a reference to this resource. First reference found was resource Patient/"+pid.getIdPart()+" in path Patient.managingOrganization", e.getMessage());
		}

		myPatientDao.delete(pid);
		myOrganizationDao.delete(oid);

	}

	@Test
	public void testDeleteAllow() throws Exception {
		myDaoConfig.setEnforceReferentialIntegrityOnDelete(false);

		Organization o = new Organization();
		o.setName("FOO");
		IIdType oid = myOrganizationDao.create(o).getId().toUnqualifiedVersionless();

		Patient p = new Patient();
		p.setManagingOrganization(new Reference(oid));
		IIdType pid = myPatientDao.create(p).getId().toUnqualifiedVersionless();

		myOrganizationDao.delete(oid);
		myPatientDao.delete(pid);

	}


}

@@ -993,19 +993,114 @@
 ete());%0A
+%09%09myDaoConfig.setEnforceReferenceTargetTypes(new DaoConfig().isEnforceReferenceTargetTypes());%0A
 %09%7D%0A
-
 %0A%09@Test%0A
@@ -1525,35 +1525,20 @@
 nceAllow
+ed
 ()
- throws Exception
  %7B%0A%09%09myD
@@ -1790,16 +1790,16 @@
 ad(id);%0A
-
 %09%09assert
@@ -1867,32 +1867,496 @@
 erence());%0A%0A%09%7D%0A%0A
+%09@Test%0A%09public void testCreateUnknownReferenceAllowed_NumericId() %7B%0A%09%09myDaoConfig.setEnforceReferentialIntegrityOnWrite(false);%0A%09%09myDaoConfig.setEnforceReferenceTargetTypes(false);%0A%0A%09%09Patient p = new Patient();%0A%09%09p.setManagingOrganization(new Reference(%22Organization/123%22));%0A%09%09IIdType id = myPatientDao.create(p).getId().toUnqualifiedVersionless();%0A%0A%09%09p = myPatientDao.read(id);%0A%09%09assertEquals(%22Organization/123%22, p.getManagingOrganization().getReference());%0A%0A%09%7D%0A%0A
 %09@Test%0A%09public v

Add test