/*
 * Copyright (c) eHealth
 */
package be.ehealth.businessconnector.ehbox.v3.session;

import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.Properties;

import org.joda.time.DateTime;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assert;
import org.junit.Assume;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import be.ehealth.businessconnector.ehbox.api.domain.Addressee;
import be.ehealth.businessconnector.ehbox.api.domain.NewsMessage;
import be.ehealth.businessconnector.ehbox.api.utils.QualityType;
import be.ehealth.businessconnector.ehbox.v3.EhboxTestDataBuilder;
import be.ehealth.businessconnector.ehbox.v3.EhboxTestUtilities;
import be.ehealth.businessconnector.ehbox.v3.builders.BuilderFactory;
import be.ehealth.businessconnector.ehbox.v3.builders.SendMessageBuilder;
import be.ehealth.businessconnector.ehbox.v3.exception.OoOPublicationException;
import be.ehealth.technicalconnector.exception.TechnicalConnectorException;
import be.ehealth.technicalconnector.session.Session;
import be.ehealth.technicalconnector.utils.IdentifierType;
import be.fgov.ehealth.ehbox.consultation.protocol.v3.DeleteOoORequest;
import be.fgov.ehealth.ehbox.consultation.protocol.v3.DeleteOoOResponse;
import be.fgov.ehealth.ehbox.consultation.protocol.v3.GetOoOListRequest;
import be.fgov.ehealth.ehbox.consultation.protocol.v3.GetOoOListResponse;
import be.fgov.ehealth.ehbox.consultation.protocol.v3.InsertOoORequest;
import be.fgov.ehealth.ehbox.consultation.protocol.v3.InsertOoOResponse;
import be.fgov.ehealth.ehbox.consultation.protocol.v3.Message;
import be.fgov.ehealth.ehbox.consultation.protocol.v3.OoO;
import be.fgov.ehealth.ehbox.core.v3.BoxIdType;
import be.fgov.ehealth.ehbox.core.v3.EhboxIdentifierType;
import be.fgov.ehealth.ehbox.publication.protocol.v3.DestinationContextType;
import be.fgov.ehealth.ehbox.publication.protocol.v3.SendMessageRequest;
import be.fgov.ehealth.ehbox.publication.protocol.v3.SendMessageResponse;
import be.fgov.ehealth.ehbox.publication.protocol.v3.Substitute;
import be.fgov.ehealth.technicalconnector.tests.session.SessionInitializer;
import be.fgov.ehealth.technicalconnector.tests.utils.TestPropertiesLoader;

/**
 * Test of {@link EhealthBoxServiceV3}.
 * 
 * @author EHP
 * 
 */
public class EhboxV3ServiceOoOIntegrationTest {

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


    private static EhealthBoxServiceV3 service;

    private static List<BoxIdType> substitutes;

    private static BoxIdType usedSubstitute;

    @BeforeClass
    public static void initSession() throws Exception {
        Properties props = TestPropertiesLoader.getProperties("/be.ehealth.businessconnector.ehboxv3.test.properties");
        Assume.assumeTrue(EhboxTestUtilities.isDoctorTest(props));
        SessionInitializer.init(props, true);
        service = ServiceFactory.getEhealthBoxServiceV3();
        substitutes = new ArrayList<BoxIdType>();
        usedSubstitute = EhboxTestDataBuilder.getInssBoxIdUser2();
        substitutes.add(usedSubstitute);
    }

    @Before
    @After
    public void initOoOEnvironment() throws Exception {
        EhboxTestUtilities.deleteAllOutOfOfficesForCurrentUser(null);
    }


    @AfterClass
    public static void unloadSession() throws Exception {
        Session.getInstance().unloadSession();
    }

    @Test
    public void testInsertOoOWithoutBoxInfo() throws Exception {
        try {


            InsertOoOResponse insertResponse = service.insertOoO(getInsertOoORequest(null));
            Assert.assertEquals("100", insertResponse.getStatus().getCode());
            String oooSavedId = insertResponse.getId();

            GetOoOListRequest getRequest = new GetOoOListRequest();
            getRequest.setBoxId(getBoxId());
            GetOoOListResponse getResponse = service.getOoOList(getRequest);
            Assert.assertEquals("100", getResponse.getStatus().getCode());

            DeleteOoORequest deleteRequest = new DeleteOoORequest();
            boolean foundId = false;
            for (OoO ooo : getResponse.getOoOs()) {
                if (oooSavedId.equals(ooo.getOoOId())) {
                    foundId = true;
                    deleteRequest.getOoOIds().add(oooSavedId);
                }
            }
            Assert.assertTrue(foundId);

            deleteRequest.setBoxId(getBoxId());
            DeleteOoOResponse deleteResponse = service.deleteOoO(deleteRequest);
            Assert.assertEquals("100", deleteResponse.getStatus().getCode());
        } catch (Exception e) {
            EhboxTestUtilities.logStackTrace(e);
            Assert.fail(e.getMessage());
        }
    }


    @Test
    public void test2Receiver() throws Exception {
        try {
            service.insertOoO(getInsertOoORequest(null));

            SendMessageRequest messageRequest = getMessageRequest();
            DestinationContextType destination = new DestinationContextType();
            destination.setId(EhboxTestDataBuilder.getInssUser1());
            destination.setQuality(QualityType.NURSE_SSIN.getQuality());
            destination.setType("SSIN");
            messageRequest.getDestinationContexts().add(destination);

            service.sendMessage(messageRequest);
            Assert.fail("must return an exception");
        } catch (OoOPublicationException te) {
            Assert.assertTrue("error code not 826", te.getErrorCode().equals("826"));
            Map<BoxIdType, List<Substitute>> oooForwardInformation = te.getOooForwardInformation();
            Assert.assertNotNull(oooForwardInformation);
            for (BoxIdType boxIdKey : oooForwardInformation.keySet()) {
                LOG.debug("test2Receiver : boxIds in forward info :" + boxIdKey.getId() + " " + boxIdKey.getType());
                List<Substitute> retrievedSubstituteList = oooForwardInformation.get(boxIdKey);
                Assert.assertEquals(1, retrievedSubstituteList.size());
                Substitute retrievedSubstitute = retrievedSubstituteList.get(0);

                Assert.assertEquals(usedSubstitute.getId(), retrievedSubstitute.getId());
                Assert.assertEquals(usedSubstitute.getQuality(), retrievedSubstitute.getQuality());
            }
        } catch (Exception e) {
            EhboxTestUtilities.logStackTrace(e);
            Assert.fail(e.getMessage());
        }

    }

    @Test
    public void testForward() throws Exception {
        try {
            InsertOoORequest insertOoORequest = getInsertOoORequest(null);
            service.insertOoO(insertOoORequest);

            BoxIdType boxSubstituteId = substitutes.get(0);

            try {
                service.sendMessage(getMessageRequest());
                Assert.fail("must return an exception");
            } catch (OoOPublicationException te) {
                Assert.assertNotNull(te.getOooForwardInformation());
                Assert.assertEquals(1, te.getOooForwardInformation().keySet().size());
                BoxIdType receiverId = getBoxId();
                BoxIdType responseId = te.getOooForwardInformation().keySet().iterator().next();
                Assert.assertEquals(receiverId.getId(), responseId.getId());
                Assert.assertEquals(receiverId.getQuality(), responseId.getQuality());
                Assert.assertEquals(1, te.getOooForwardInformation().get(responseId).size());
                Substitute substituteId = te.getOooForwardInformation().get(responseId).get(0);
                Assert.assertEquals(boxSubstituteId.getId(), substituteId.getId());
                Assert.assertEquals(boxSubstituteId.getQuality(), substituteId.getQuality());
            }
        } catch (Exception e) {
            EhboxTestUtilities.logStackTrace(e);
            Assert.fail(e.getMessage());
        }
    }

    @Test
    public void testForceSendMessage() throws Exception {
        try {
            service.insertOoO(getInsertOoORequest(null));
            SendMessageRequest messageRequest = getMessageRequest();
            for (EhboxIdentifierType identifier : messageRequest.getDestinationContexts()) {
                DestinationContextType destination = (DestinationContextType) identifier;
                destination.setOoOProcessed(Boolean.TRUE);
            }
            SendMessageResponse messageResponse = service.sendMessage(messageRequest);
            Assert.assertEquals("100", messageResponse.getStatus().getCode());
        } catch (Exception e) {
            EhboxTestUtilities.logStackTrace(e);
            Assert.fail(e.getMessage());
        }
    }


    /**
     * @param boxId
     */
    private BoxIdType getBoxId() {
        return EhboxTestDataBuilder.getInssBoxIdUser1();

    }

    private InsertOoORequest getInsertOoORequest(BoxIdType boxId) throws TechnicalConnectorException {
        DateTime startDate = new DateTime(System.currentTimeMillis());
        DateTime endDate = startDate.plusWeeks(2);
        return BuilderFactory.getRequestBuilder().createInsertOoORequest(boxId, startDate, endDate, substitutes);
    }

    private SendMessageRequest getMessageRequest() throws Exception {
        // Creating destination List
        List<Addressee> addresseeList = new ArrayList<Addressee>();
        Addressee addressee = new Addressee(IdentifierType.SSIN);
        addressee.setId(EhboxTestDataBuilder.getInssUser1());
        addressee.setQuality(QualityType.DOCTOR_SSIN);
        addresseeList.add(addressee);

        // Creating the news
        SendMessageBuilder builder = BuilderFactory.getSendMessageBuilder();

        NewsMessage<Message> news = new NewsMessage<Message>();
        news.getDocument().setTitle("News " + new Date());
        news.getDocument().setContent("eureka".getBytes());
        news.setDestinations(addresseeList);
        // news.setSender(addressee);
        news.getDocument().setFilename("test.txt");
        news.setImportant(true);
        news.setEncrypted(false);

        return builder.buildMessage(news);
    }

}
