package gov.va.med.edp.rpc;

import gov.va.med.vistalink.adapter.record.LoginsDisabledFaultException;
import gov.va.med.vistalink.adapter.record.VistaLinkFaultException;
import gov.va.med.vistalink.rpc.NoRpcContextFaultException;
import gov.va.med.vistalink.rpc.RpcNotInContextFaultException;
import gov.va.med.vistalink.rpc.RpcNotOkForProxyUseException;
import gov.va.med.vistalink.security.m.SecurityAccessVerifyCodePairInvalidException;
import org.springframework.dao.DataAccessResourceFailureException;
import org.springframework.dao.DataRetrievalFailureException;
import org.springframework.dao.PermissionDeniedDataAccessException;

public class VistaLinkRpcTemplateTest extends AbstractVistaLinkConnectionTest {

    private static final String TEST_DUZ = "1234567";
    protected static final String TEST_RPC_CONTEXT = "FOO RPC CONTEXT";
    protected static final String TEST_RPC = "FOO BAR RPC";
    protected static final String TEST_DIVISION = "500";

    public void testExecuteRpcAsUserNoParams() {
        expectVistaLinkDuzConnection(TEST_DUZ);
        expectRpcAndReturn(TEST_RPC_CONTEXT, TEST_RPC, "<foo/>");

        replay();

        VistaLinkRpcTemplate t = new VistaLinkRpcTemplate(mockConnectionFactoryLocator);

        String result = t.rpcAsUser(TEST_DIVISION, TEST_DUZ, TEST_RPC_CONTEXT, TEST_RPC);
        assertEquals("<foo/>", result);

        verify();
    }

    public void testExecuteRpcAsApplicationNoParams() {
        expectVistaLinkAppProxyConnection(TEST_DUZ);
        expectRpcAndReturn(TEST_RPC_CONTEXT, TEST_RPC, "<foo/>");

        replay();

        VistaLinkRpcTemplate t = new VistaLinkRpcTemplate(mockConnectionFactoryLocator);

        String result = t.rpcAsApplication(TEST_DIVISION, TEST_DUZ, TEST_RPC_CONTEXT, TEST_RPC);
        assertEquals("<foo/>", result);

        verify();
    }

    public void testDataAccessResourceFailureExceptionFromLocator() {
        VistaLinkRpcTemplate t = new VistaLinkRpcTemplate(mockConnectionFactoryLocator);
        try {
            t.rpcAsUser("600", TEST_DUZ, TEST_RPC_CONTEXT, TEST_RPC); // locator can only find station 500
            fail("expected data access resource failure exception");
        } catch (DataAccessResourceFailureException e) {
            // NOOP
        }
    }

    public void testVistaLinkFaultException() {
        assertExceptionDuringRpc(DataRetrievalFailureException.class, new VistaLinkFaultException("foo bar baz"));
    }

    public void testSecurityFaultException() {
        assertExceptionDuringRpc(VistaLinkRpcPermissionDeniedException.class, new SecurityAccessVerifyCodePairInvalidException(new VistaLinkFaultException("foo bar baz")));
    }

    public void testRpcNotInContextException() {
        assertExceptionDuringRpc(VistaLinkRpcPermissionDeniedException.class, new RpcNotInContextFaultException(new VistaLinkFaultException("foo bar baz")));
    }


    public void testNoRpcContextException() {
        assertExceptionDuringRpc(VistaLinkRpcInvalidApiUsageException.class, new NoRpcContextFaultException(new VistaLinkFaultException("foo bar baz")));
    }

    public void testRpcNotOkForProxyUseException() {
        expectVistaLinkAppProxyConnection(TEST_DUZ);
        expectRpcAndDefaultThrow(TEST_RPC_CONTEXT, TEST_RPC, new RpcNotOkForProxyUseException(new VistaLinkFaultException("foo bar baz")));

        replay();

        VistaLinkRpcTemplate t = new VistaLinkRpcTemplate(mockConnectionFactoryLocator);
        try {
            t.rpcAsApplication(TEST_DIVISION, TEST_DUZ, TEST_RPC_CONTEXT, TEST_RPC);
            fail("expected permission denied exception");
        } catch (VistaLinkRpcInvalidApiUsageException e) {
            // NOOP
        }
        verify();
    }

    public void testLoginsDisabledException() {
        assertExceptionDuringRpc(DataAccessResourceFailureException.class, new LoginsDisabledFaultException(new VistaLinkFaultException("foo bar baz")));
    }

    public void assertExceptionDuringRpc(Class expectedException, Throwable throwDuringRpc) {
        expectVistaLinkDuzConnection(TEST_DUZ);
        expectVistaLinkAppProxyConnection(TEST_DUZ);
        expectRpcAndDefaultThrow(TEST_RPC_CONTEXT, TEST_RPC, throwDuringRpc);

        replay();

        VistaLinkRpcTemplate t = new VistaLinkRpcTemplate(mockConnectionFactoryLocator);
        try {
            t.rpcAsUser(TEST_DIVISION, TEST_DUZ, TEST_RPC_CONTEXT, TEST_RPC);
            fail("expected " + expectedException.getName());
        } catch (Exception e) {
            assertTrue(expectedException.isAssignableFrom(e.getClass()));
        }

        try {
            t.rpcAsApplication(TEST_DIVISION, TEST_DUZ, TEST_RPC_CONTEXT, TEST_RPC);
            fail("expected " + expectedException.getName());
        } catch (Exception e) {
            assertTrue(expectedException.isAssignableFrom(e.getClass()));
        }

        verify();
    }

    protected String getStationNumber() {
        return TEST_DIVISION;
    }
}
