class TestSkillBuilder(unittest.TestCase):
    def setUp(self):
        self.sb = SkillBuilder()

    def test_skill_configuration_getter_no_registered_components(self):
        actual_config = self.sb.skill_configuration

        assert actual_config.request_mappers is not None, (
            "Skill Configuration getter in Skill Builder didn't set request "
            "mappers correctly")
        assert actual_config.request_mappers[
            0].request_handler_chains is not None, (
                "Skill Configuration getter in Skill Builder didn't set handler "
                "chains in request mappers correctly")
        assert len(
            actual_config.request_mappers[0].request_handler_chains) == 0, (
                "Skill Configuration getter in Skill Builder added invalid "
                "handler in handler chain, "
                "when no request handlers are registered")
        assert actual_config.handler_adapters is not None, (
            "Skill Configuration getter in Skill Builder didn't set handler "
            "adapters correctly")
        assert isinstance(
            actual_config.handler_adapters[0], GenericHandlerAdapter
        ), ("Skill Configuration getter in Skill Builder didn't set default "
            "handler adapter")
        assert isinstance(
            actual_config.exception_mapper, GenericExceptionMapper), (
                "Skill Configuration getter in Skill Builder created invalid "
                "exception mapper, "
                "when no exception handlers are registered")
        assert len(actual_config.exception_mapper.exception_handlers) == 0, (
            "Skill Configuration getter in Skill Builder created invalid "
            "exception handlers in exception mapper, "
            "when no exception handlers are registered")
        assert actual_config.request_interceptors == [], (
            "Skill Configuration getter in Skill Builder created invalid "
            "request interceptors, "
            "when no global request interceptors are registered")
        assert actual_config.response_interceptors == [], (
            "Skill Configuration getter in Skill Builder created invalid "
            "response interceptors, "
            "when no global response interceptors are registered")
        assert actual_config.custom_user_agent is None, (
            "Skill Configuration getter in Skill Builder set invalid custom "
            "user agent")
        assert actual_config.skill_id is None, (
            "Skill Configuration getter in Skill Builder set invalid skill id")

    def test_skill_configuration_getter_handlers_registered(self):
        mock_request_handler = mock.MagicMock(spec=AbstractRequestHandler)
        self.sb.add_request_handler(request_handler=mock_request_handler)

        mock_exception_handler = mock.MagicMock(spec=AbstractExceptionHandler)
        self.sb.add_exception_handler(exception_handler=mock_exception_handler)

        actual_config = self.sb.skill_configuration

        assert actual_config.request_mappers is not None, (
            "Skill Configuration getter in Skill Builder didn't set request "
            "mappers correctly")
        assert actual_config.request_mappers[
            0].request_handler_chains is not None, (
                "Skill Configuration getter in Skill Builder didn't set handler "
                "chains in request mappers correctly")
        assert len(
            actual_config.request_mappers[0].request_handler_chains) == 1, (
                "Skill Configuration getter in Skill Builder didn't add valid "
                "handler in handler chain, "
                "when request handlers are registered")
        assert actual_config.request_mappers[0].request_handler_chains[
            0].request_handler == mock_request_handler, (
                "Skill Configuration getter in Skill Builder added invalid "
                "handler in handler chain, "
                "when request handlers are registered")

        assert actual_config.exception_mapper is not None, (
            "Skill Configuration getter in Skill Builder didn't create "
            "exception mapper, "
            "when exception handlers are registered")
        assert len(actual_config.exception_mapper.exception_handlers) == 1, (
            "Skill Configuration getter in Skill Builder added additional "
            "exception handlers than the registered ones "
            "in exception mapper")
        assert actual_config.exception_mapper.exception_handlers[
            0] == mock_exception_handler, (
                "Skill Configuration getter in Skill Builder added invalid "
                "handler in exception mapper, "
                "when exception handlers are registered")

    def test_create_skill(self):
        mock_request_handler = mock.MagicMock(spec=AbstractRequestHandler)
        self.sb.add_request_handler(request_handler=mock_request_handler)

        mock_exception_handler = mock.MagicMock(spec=AbstractExceptionHandler)
        self.sb.add_exception_handler(exception_handler=mock_exception_handler)

        actual_skill = self.sb.create()
        expected_skill = CustomSkill(self.sb.skill_configuration)

        assert actual_skill.request_dispatcher.request_mappers[0].request_handler_chains[0].request_handler == \
            expected_skill.request_dispatcher.request_mappers[0].request_handler_chains[0].request_handler, (
            "Skill Builder created skill with incorrect request handlers when "
            "using create method")

        assert actual_skill.request_dispatcher.exception_mapper.exception_handlers[0] == \
            expected_skill.request_dispatcher.exception_mapper.exception_handlers[0], (
            "Skill Builder created skill with incorrect exception handlers "
            "when using create method")

    def test_lambda_handler_creation(self):
        handler_func = self.sb.lambda_handler()
        assert callable(handler_func), "Skill Builder Lambda Handler " \
                                       "function returned an invalid object"

        actual_arg_spec = inspect.getargspec(handler_func)
        assert len(actual_arg_spec.args) == 2, (
            "Skill Builder Lambda Handler function created a handler of "
            "different signature than AWS Lambda")
        assert "event" in actual_arg_spec.args, (
            "Skill Builder Lambda Handler function created a handler without "
            "named parameter event")
        assert "context" in actual_arg_spec.args, (
            "Skill Builder Lambda Handler function created a handler without "
            "named parameter context")

    def test_lambda_handler_invocation(self):
        mock_request_handler = mock.MagicMock(spec=AbstractRequestHandler)
        mock_request_handler.can_handle.return_value = True
        mock_response = Response()
        mock_response.output_speech = "test output speech"
        mock_request_handler.handle.return_value = mock_response
        self.sb.add_request_handler(request_handler=mock_request_handler)

        mock_request_envelope_payload = {
            "context": {
                "System": {
                    "application": {
                        "applicationId": "test"
                    }
                }
            },
            "session": {
                "new": "True"
            }
        }

        self.sb.skill_id = "test"
        lambda_handler = self.sb.lambda_handler()

        response_envelope = lambda_handler(event=mock_request_envelope_payload,
                                           context=None)

        assert response_envelope["version"] == RESPONSE_FORMAT_VERSION, (
            "Response Envelope from lambda handler invocation has version "
            "different than expected")
        assert response_envelope["userAgent"] == user_agent_info(
            sdk_version=__version__, custom_user_agent=None
        ), ("Response Envelope from lambda handler invocation has user agent "
            "info different than expected")
        assert response_envelope["response"][
            "outputSpeech"] == "test output speech", (
                "Response Envelope from lambda handler invocation has incorrect "
                "response than built by skill")

    def test_out_of_session_lambda_handler_invocation(self):
        mock_request_handler = mock.MagicMock(spec=AbstractRequestHandler)
        mock_request_handler.can_handle.return_value = True
        mock_response = Response()
        mock_response.output_speech = "test output speech"
        mock_request_handler.handle.return_value = mock_response
        self.sb.add_request_handler(request_handler=mock_request_handler)

        mock_request_envelope_payload = {
            "context": {
                "System": {
                    "application": {
                        "applicationId": "test"
                    }
                }
            }
        }

        self.sb.skill_id = "test"
        lambda_handler = self.sb.lambda_handler()

        response_envelope = lambda_handler(event=mock_request_envelope_payload,
                                           context=None)

        assert response_envelope["version"] == RESPONSE_FORMAT_VERSION, (
            "Response Envelope from lambda handler invocation has version "
            "different than expected")
        assert response_envelope["userAgent"] == user_agent_info(
            sdk_version=__version__, custom_user_agent=None
        ), ("Response Envelope from lambda handler invocation has user agent "
            "info different than expected")
        assert response_envelope["response"][
            "outputSpeech"] == "test output speech", (
                "Response Envelope from lambda handler invocation has incorrect "
                "response than built by skill")

    def test_should_append_additional_user_agent(self):
        additional_user_agent = "test_string"
        sdk_user_agent = user_agent_info(sdk_version=__version__)
        mock_request_handler = mock.MagicMock(spec=AbstractRequestHandler)
        mock_request_handler.can_handle.return_value = True
        mock_response = Response()
        mock_request_handler.handle.return_value = mock_response
        self.sb.add_request_handler(request_handler=mock_request_handler)
        self.sb.add_custom_user_agent(user_agent=additional_user_agent)

        mock_request_envelope_payload = {
            "context": {
                "System": {
                    "application": {
                        "applicationId": "test"
                    }
                }
            }
        }

        self.sb.skill_id = "test"
        lambda_handler = self.sb.lambda_handler()

        response_envelope = lambda_handler(event=mock_request_envelope_payload,
                                           context=None)

        self.assertEqual("{} {}".format(additional_user_agent, sdk_user_agent),
                         response_envelope["userAgent"],
                         "Response envelope doesn't have correct user agent")

    def test_should_append_additional_user_agent_using_userAgentManager(self):
        additional_user_agent = "test_string"
        sdk_user_agent = user_agent_info(sdk_version=__version__)
        mock_request_handler = mock.MagicMock(spec=AbstractRequestHandler)
        mock_request_handler.can_handle.return_value = True
        mock_response = Response()
        mock_request_handler.handle.return_value = mock_response
        self.sb.add_request_handler(request_handler=mock_request_handler)

        mock_request_envelope_payload = {
            "context": {
                "System": {
                    "application": {
                        "applicationId": "test"
                    }
                }
            }
        }

        self.sb.skill_id = "test"
        lambda_handler = self.sb.lambda_handler()

        UserAgentManager.register_component(
            component_name=additional_user_agent)

        response_envelope = lambda_handler(event=mock_request_envelope_payload,
                                           context=None)

        self.assertEqual(
            "{} {}".format(additional_user_agent,
                           sdk_user_agent), response_envelope["userAgent"],
            "Response envelope doesn't have correct user agent when adding "
            "using UserAgentManager")

    def tearDown(self):
        UserAgentManager.clear()