package com.capgemini.reports.common;

import com.capgemini.framework.teamcenter.authent.TcSession;
import com.capgemini.framework.teamcenter.exceptions.KurtException;
import com.capgemini.reports.exceptions.InvalidUserInputException;
import com.capgemini.reports.exceptions.UserInputErrorEnum;
import lombok.extern.slf4j.Slf4j;
import org.json.JSONObject;
import org.junit.Assert;
import org.junit.Test;
import org.springframework.mock.web.MockHttpServletRequest;
import org.springframework.mock.web.MockHttpServletResponse;

import javax.jms.JMSException;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException;

/** JUnit test. **/
@Slf4j
public class AbstractKurtServletTest {

    private static final String STATUS_TOKEN = "status";
    private static final String STATUS_SUCCESS = "success";
    private static final String STATUS_FAILED = "failed";

    private static final String SUCCESS_TOKEN = "success";
    private static final String SUCCESS_MESSAGE = "Success message";

    private static final String FAILURE_TOKEN = "error";
    private static final String FAILURE_MESSAGE = "Expected Generic Failure message";

    private static final UserInputErrorEnum EXPECTED_BAD_SERVLET_ERROR = UserInputErrorEnum.INCORRECT_PRODUCT;

    /** JUnit test. **/
    @Test
    public void testSuccessMessage() {
        JSONObject json = ServletMessageHelper.successMessage(SUCCESS_MESSAGE);
        Assert.assertEquals(STATUS_SUCCESS, json.get(STATUS_TOKEN));
        Assert.assertEquals(SUCCESS_MESSAGE, json.getString(SUCCESS_TOKEN));
    }

    /** JUnit test. **/
    @Test
    public void testErrorMessage1() {
        JSONObject json = ServletMessageHelper.errorMessage(FAILURE_MESSAGE);
        Assert.assertEquals(STATUS_FAILED, json.get(STATUS_TOKEN));
        Assert.assertEquals(FAILURE_MESSAGE, json.getString(FAILURE_TOKEN));
    }

    /** JUnit test. **/
    @Test
    public void testErrorMessage2() {
        JSONObject json = ServletMessageHelper.errorMessage(new KurtException(FAILURE_MESSAGE));
        Assert.assertEquals(STATUS_FAILED, json.get(STATUS_TOKEN));
        Assert.assertEquals(FAILURE_MESSAGE, json.getString(FAILURE_TOKEN));
    }

    /** JUnit test. **/
    @Test
    public void testErrorMessage3() {
        UserInputErrorEnum expectedError = UserInputErrorEnum.PRODUCT_DOES_NOT_EXIST_NO_DATA_TO_PRINT;
        JSONObject json = ServletMessageHelper.errorMessage(new InvalidUserInputException(expectedError));
        Assert.assertEquals(STATUS_FAILED, json.get(STATUS_TOKEN));
        Assert.assertEquals(expectedError.getMsgFr(), json.getString(FAILURE_TOKEN));
    }

    /**
     * JUnit test.
     *
     * @throws ServletException should not happen
     * @throws IOException should not happen
     **/
    @Test
    public void testDoPostSuccess() throws ServletException, IOException {
        // Test the servlet
        JSONObject responseJson = testSomeServlet(new SomeGoodServlet());

        // Parse the contents
        String resultStr = responseJson.getString(ServletMessageHelper.TOKEN_STATUS);
        log.info("Json object received with status = \"" + resultStr + "\"");
        Assert.assertEquals(ServletMessageHelper.STATUS_SUCCESS, resultStr);
        Assert.assertEquals(SUCCESS_MESSAGE, responseJson.get(ServletMessageHelper.STATUS_SUCCESS));
    }

    /**
     * JUnit test.
     *
     * @throws ServletException should not happen
     * @throws IOException should not happen
     **/
    @Test
    public void testDoPostKurtFailure() throws ServletException, IOException {
        // Test the servlet
        JSONObject responseJson = testSomeServlet(new SomeBadServletWithBadJMScommunication());

        // Parse the contents
        String resultStr = responseJson.getString(ServletMessageHelper.TOKEN_STATUS);
        log.info("Json object received with status = \"" + resultStr + "\"");
        Assert.assertEquals(ServletMessageHelper.STATUS_FAILED, resultStr);
        Assert.assertEquals(ServletMessageHelper.POSTING_ERROR_MESSAGE_FR, responseJson.get(ServletMessageHelper.TOKEN_ERROR));
    }

    /**
     * JUnit test.
     *
     * @throws ServletException should not happen
     * @throws IOException should not happen
     **/
    @Test
    public void testDoPostServletFailure() throws ServletException, IOException {
        // Test the servlet
        JSONObject responseJson = testSomeServlet(new SomeBadServletWithNiceExeption());

        // Parse the contents
        String resultStr = responseJson.getString(ServletMessageHelper.TOKEN_STATUS);
        log.info("Json object received with status = \"" + resultStr + "\"");
        Assert.assertEquals(ServletMessageHelper.STATUS_FAILED, resultStr);
        Assert.assertEquals(EXPECTED_BAD_SERVLET_ERROR.getMsgFr(), responseJson.get(ServletMessageHelper.TOKEN_ERROR));
    }

    /**
     * JUnit test.
     *
     * @param testerServlet should not happen
     * @return JSON object should not happen
     * @throws ServletException should not happen
     * @throws IOException should not happen
     **/
    public JSONObject testSomeServlet(final AbstractKurtServlet testerServlet) throws ServletException, IOException {

        // Setup request and responses
        MockHttpServletRequest request = new MockHttpServletRequest();
        MockHttpServletResponse response = new MockHttpServletResponse();
        log.info("Request and Response ready");

        // Create Servlet instance and test it
        testerServlet.doPost(request, response);
        log.info("doPost() Done");

        // Obtain response content
        String responseStr = response.getContentAsString();
        log.info("Raw response = \"" + responseStr + "\"");

        // Obtain response status
        return new JSONObject(responseStr);
    }

    /** Servlet sample for test purpose. **/
    public class SomeGoodServlet extends AbstractKurtServlet {
        private static final long serialVersionUID = 8779144588360308332L;

        @Override
        protected JSONObject perform(final HttpServletRequest request, final TcSession session) {
            return ServletMessageHelper.successMessage(SUCCESS_MESSAGE);
        }
    }

    /** Servlet sample for test purpose. **/
    private class SomeBadServletWithBadJMScommunication extends AbstractKurtServlet {
        private static final long serialVersionUID = 7423523975629997878L;

        @Override
        protected JSONObject perform(final HttpServletRequest request, final TcSession session) throws JMSException {
            throw new JMSException(FAILURE_MESSAGE);
        }
    }

    private class SomeBadServletWithNiceExeption extends AbstractKurtServlet {
        private static final long serialVersionUID = 7423523975629997878L;

        @Override
        protected JSONObject perform(final HttpServletRequest request, final TcSession session) throws InvalidUserInputException {
            throw new InvalidUserInputException(UserInputErrorEnum.INCORRECT_PRODUCT);
        }
    }

}
