package com.avaya.zephyr.services.dynamicteamformation.sms;

import static org.easymock.EasyMock.anyObject;
import static org.easymock.EasyMock.expect;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.powermock.api.easymock.PowerMock.createMock;
import static org.powermock.api.easymock.PowerMock.expectLastCall;
import static org.powermock.api.easymock.PowerMock.expectNew;
import static org.powermock.api.easymock.PowerMock.mockStatic;
import static org.powermock.api.easymock.PowerMock.replayAll;
import static org.powermock.api.easymock.PowerMock.verifyAll;

import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.List;

import javax.servlet.http.HttpServletRequest;

import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import com.avaya.collaboration.businessdata.api.NoAttributeFoundException;
import com.avaya.collaboration.businessdata.api.ServiceData;
import com.avaya.collaboration.conference.scheduled.SchedConf;
import com.avaya.collaboration.sms.SmsFactory;
import com.avaya.collaboration.sms.SmsRequest;
import com.avaya.collaboration.util.logger.Logger;

@RunWith(PowerMockRunner.class)
@PrepareForTest(
{ DynamicTeamFormationSmsSender.class, SmsRequest.class, SmsFactory.class,
        DynamicTeamFormationSmsListener.class })
public class DynamicTeamFormationSmsSenderTest
{
    private static final String SMS_PARAM_HTTP_TO = "smsTo";
    private static final String SMS_INFO_NO_TO_LOG = "Info: No SMS recipients specified in the HTTP request.";
    private static final String SMS_INFO_NOT_SENT_LOG = "Info: SMS will not be sent.";
    private static final String SMS_PARAM_HTTP_BODY = "smsBody";
    private static final String SMS_INFO_NO_BODY_LOG = "Info: No SMS body specified in HTTP request.";
    private static final String SMS_PARAM_SMGR_FROM = "smsFrom";
    private static final String SMS_ERROR_FROM_LOG =
            "Error: Error occured acquiring 'from' SMS number from SMGR.";
    private static final String SMS_INFO_NO_FROM_LOG =
            "Info: No 'from' sms number specified in the DynamicTeamFormationService attribute page on SMGR.";

    private DynamicTeamFormationSmsSender dynamicTeamFormationSmsSenderTest;
    private Logger mockLogger;
    private PrintWriter mockPrintWriter;
    private HttpServletRequest mockHttpServletRequest;
    private ServiceData mockServiceData;
    private SmsRequest mockSmsRequest;
    private SchedConf mockSchedConf;
    private DynamicTeamFormationSmsListener mockDynamicTeamFormationSmsListener;

    @Before
    public void setUpMockCommon() throws Exception
    {
        mockLogger = createMock(Logger.class);
        mockPrintWriter = createMock(PrintWriter.class);
        mockServiceData = createMock(ServiceData.class);
        mockHttpServletRequest = createMock(HttpServletRequest.class);
        mockSmsRequest = createMock(SmsRequest.class);
        mockSchedConf = createMock(SchedConf.class);
        mockDynamicTeamFormationSmsListener =
                createMock(DynamicTeamFormationSmsListener.class, mockSmsRequest);

        dynamicTeamFormationSmsSenderTest =
                new DynamicTeamFormationSmsSender(mockServiceData, mockHttpServletRequest,
                        mockPrintWriter, mockLogger);
    }

    private void setupMockSmsTo(String[] smsTo)
    {
        expect(mockHttpServletRequest
                .getParameterValues(SMS_PARAM_HTTP_TO))
                .andReturn(smsTo);

        boolean smsToEveryEntryEmpty = true;
        if (smsTo != null)
        {
            for (String smsToEntry : smsTo)
            {
                if (!smsToEntry.isEmpty())
                {
                    smsToEveryEntryEmpty = false;
                    break;
                }
            }
        }

        if (smsTo == null || smsToEveryEntryEmpty)
        {
            setupMockLogHttpResponseInfo(SMS_INFO_NO_TO_LOG);
            setupMockLogHttpResponseInfo(SMS_INFO_NOT_SENT_LOG);
        }
    }

    private void setupMockSmsBody(String[] smsBody)
    {

        expect(mockHttpServletRequest
                .getParameterValues(SMS_PARAM_HTTP_BODY))
                .andReturn(smsBody);

        boolean smsBodyEveryEntryEmpty = true;
        if (smsBody != null)
        {
            for (String smsToEntry : smsBody)
            {
                if (!smsToEntry.isEmpty())
                {
                    smsBodyEveryEntryEmpty = false;
                    break;
                }
            }
        }

        if (smsBody == null || smsBodyEveryEntryEmpty)
        {
            setupMockLogHttpResponseInfo(SMS_INFO_NO_BODY_LOG);
            setupMockLogHttpResponseInfo(SMS_INFO_NOT_SENT_LOG);
        }
        else
        {
            expect(mockSchedConf.getUrl()).andReturn("mockUrl");
        }
    }

    private void setupMockSmsFrom(String smsFrom) throws Exception
    {
        if (smsFrom == null)
        {
            expect(mockServiceData
                    .getServiceAttribute(SMS_PARAM_SMGR_FROM))
                    .andThrow(new NoAttributeFoundException(
                            SMS_PARAM_SMGR_FROM));
            setupMockLogHttpResponseError(SMS_ERROR_FROM_LOG);
            // setupMockLogHttpResponseInfo(SMS_INFO_NOT_SENT_LOG);
        }
        else
        {
            expect(mockServiceData
                    .getServiceAttribute(SMS_PARAM_SMGR_FROM))
                    .andReturn(smsFrom);
            if (smsFrom.isEmpty())
            {
                setupMockLogHttpResponseInfo(SMS_INFO_NO_FROM_LOG);
                // setupMockLogHttpResponseInfo(SMS_INFO_NOT_SENT_LOG);
            }
        }
    }

    @SuppressWarnings("unchecked")
    private void setupMockSmsRequest() throws Exception
    {
        mockStatic(SmsFactory.class);
        expect(SmsFactory.createSmsRequest((List<String>) anyObject(),
                (String) anyObject())).andReturn(mockSmsRequest);
        expect(mockSmsRequest.setSender((String) anyObject())).andReturn(mockSmsRequest);
        expectNew(DynamicTeamFormationSmsListener.class, mockSmsRequest).andReturn(
                mockDynamicTeamFormationSmsListener);
        expect(mockSmsRequest.setListener(mockDynamicTeamFormationSmsListener)).andReturn(mockSmsRequest);
        mockSmsRequest.send();
        expectLastCall();
        expect(mockSmsRequest.getRecipients()).andReturn(new ArrayList<String>());
        setupMockLogHttpResponseInfo(null);
    }

    @SuppressWarnings("unchecked")
    private void setupMockSmsRequestWithNoSender() throws Exception
    {
        mockStatic(SmsFactory.class);
        expect(SmsFactory.createSmsRequest((List<String>) anyObject(),
                (String) anyObject())).andReturn(mockSmsRequest);
        expectNew(DynamicTeamFormationSmsListener.class, mockSmsRequest).andReturn(
                mockDynamicTeamFormationSmsListener);
        expect(mockSmsRequest.setListener(mockDynamicTeamFormationSmsListener)).andReturn(mockSmsRequest);
        mockSmsRequest.send();
        expectLastCall();
        expect(mockSmsRequest.getRecipients()).andReturn(new ArrayList<String>());
        setupMockLogHttpResponseInfo(null);
    }

    private void setupMockLogHttpResponseInfo(String logInfo)
    {
        if (logInfo == null)
        {
            mockLogger.info((String) anyObject());
            expectLastCall();
            mockPrintWriter.println((String) anyObject());
            expectLastCall();
        }
        else
        {
            mockLogger.info(logInfo);
            expectLastCall();
            mockPrintWriter.println(logInfo);
            expectLastCall();
        }
    }

    private void setupMockLogHttpResponseError(String logError)
    {
        if (logError == null)
        {
            mockLogger.error((String) anyObject());
            expectLastCall();
            mockPrintWriter.println((String) anyObject());
            expectLastCall();
        }
        else
        {
            mockLogger.error((String) anyObject(), (Exception) anyObject());
            expectLastCall();
            mockPrintWriter.println(logError);
            expectLastCall();
        }
    }

    @Test
    public void testSendSms() throws Exception
    {
        // Test Info
        // sendSms needs the HTTP request to have the 'to',
        // and 'body' SMS fields, and the SMGR attribute 'SMS
        // from' field to be present

        // Test Data
        final String[] smsToMultipleCommaMixed =
        { "111@domain.com", "222@domain.com,333@domain.com" };
        final String[] smsBody =
        { "test body" };
        final String smsFrom = "from@domain.com";

        // Setup mocks
        setupMockSmsTo(smsToMultipleCommaMixed);
        setupMockSmsBody(smsBody);
        setupMockSmsFrom(smsFrom);
        setupMockSmsRequest();

        // Replay, Execute, and Verify
        replayAll();
        assertTrue(dynamicTeamFormationSmsSenderTest.sendSms(mockSchedConf));
        verifyAll();
    }

    @Test
    public void testSendSmsToNull() throws Exception
    {
        // Test Info
        // sendSms needs the HTTP request to have the 'to',
        // and 'body' sms fields.

        // Test Data
        final String[] smsToNull = null;
        final String[] smsBody =
        { "test body" };

        // Setup mocks
        setupMockSmsTo(smsToNull);
        setupMockSmsBody(smsBody);

        // Replay, Execute, and Verify
        replayAll();
        assertFalse(dynamicTeamFormationSmsSenderTest.sendSms(mockSchedConf));
        verifyAll();
    }

    @Test
    public void testSendSmsToEmpty() throws Exception
    {
        // Test Info
        // sendSms needs the HTTP request to have the 'to',
        // and 'body' sms fields.

        // Test Data
        final String[] smsToEmpty =
        { "" };
        final String[] smsBody =
        { "test body" };

        // Setup mocks
        setupMockSmsTo(smsToEmpty);
        setupMockSmsBody(smsBody);

        // Replay, Execute, and Verify
        replayAll();
        assertFalse(dynamicTeamFormationSmsSenderTest.sendSms(mockSchedConf));
        verifyAll();
    }

    @Test
    public void testSendSmsBodyNull() throws Exception
    {
        // Test Info
        // sendSms needs the HTTP request to have the 'to',
        // and 'body' sms fields.

        // Test Data
        final String[] smsToMultipleCommaMixed =
        { "to1@domain.com", "to2@domain.com,to3@domain.com" };
        final String[] smsBodyNull = null;

        // Setup mocks
        setupMockSmsTo(smsToMultipleCommaMixed);
        setupMockSmsBody(smsBodyNull);

        // Replay, Execute, and Verify
        replayAll();
        assertFalse(dynamicTeamFormationSmsSenderTest.sendSms(mockSchedConf));
        verifyAll();
    }

    @Test
    public void testSendSmsBodyEmpty() throws Exception
    {
        // Test Info
        // sendSms needs the HTTP request to have the 'to',
        // and 'body' sms fields.

        // Test Data
        final String[] smsToMultipleCommaMixed =
        { "to1@domain.com", "to2@domain.com,to3@domain.com" };
        final String[] smsBodyEmpty =
        { "" };

        // Setup mocks
        setupMockSmsTo(smsToMultipleCommaMixed);
        setupMockSmsBody(smsBodyEmpty);

        // Replay, Execute, and Verify
        replayAll();
        assertFalse(dynamicTeamFormationSmsSenderTest.sendSms(mockSchedConf));
        verifyAll();
    }

    @Test
    public void testSendSmsFromEmpty() throws Exception
    {
        // Test info
        // sendSms needs the HTTP request to have the 'to',
        // and 'body' sms fields, and the SMGR attribute 'sms
        // from' field to be present

        // Test Data
        final String[] smsToMultipleCommaMixed =
        { "to1@domain.com", "to2@domain.com,to3@domain.com" };
        final String[] smsBody =
        { "test body" };
        final String smsFromEmpty = "";

        // Setup mocks
        setupMockSmsTo(smsToMultipleCommaMixed);
        setupMockSmsBody(smsBody);
        setupMockSmsFrom(smsFromEmpty);
        setupMockSmsRequestWithNoSender();

        // Replay, Execute, and Verify
        replayAll();
        assertTrue(dynamicTeamFormationSmsSenderTest.sendSms(mockSchedConf));
        verifyAll();
    }

    @Test
    public void testSendSmsFromException() throws Exception
    {
        // Test Info
        // sendSms needs the HTTP request to have the 'to',
        // and 'body' sms fields, and the SMGR attribute 'sms
        // from' field to be present

        // Test Data
        final String[] smsToMultipleCommaMixed =
        { "to1@domain.com", "to2@domain.com,to3@domain.com" };
        final String[] smsBody =
        { "test body" };
        final String smsFromNull = null;

        // Setup mocks
        setupMockSmsTo(smsToMultipleCommaMixed);
        setupMockSmsBody(smsBody);
        setupMockSmsFrom(smsFromNull);
        setupMockSmsRequestWithNoSender();

        // Replay, Execute, and Verify
        replayAll();
        assertTrue(dynamicTeamFormationSmsSenderTest.sendSms(mockSchedConf));
        verifyAll();
    }
}
