# Copyright 2017 Mycroft AI Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Mycroft's intent service, providing intent parsing since forever!"""
from mycroft.metrics import report_timing
from mycroft.skills.intent_services import (
    IntentMatch
)
from ovos_bus_client.message import Message
from ovos_core.intent_services import IntentService as _IS
from ovos_utils.log import LOG
# compat imports
from ovos_workshop.intents import open_intent_envelope


class IntentService(_IS):
    """Mycroft intent service. parses utterances using a variety of systems.

    The intent service also provides the internal API for registering and
    querying the intent service.
    """

    def do_converse(self, utterances, skill_id, lang, message):
        """DEPRECATED: do not use, method only for api backwards compatibility

        Logs a warning and calls ConverseService.converse

        Args:
            utterances (list of tuples): utterances paired with normalized
                                         versions.
            skill_id: skill to query.
            lang (str): current language
            message (Message): message containing interaction info.
        """
        # NOTE: can not delete method for backwards compat with upstream
        LOG.warning("self.do_converse has been deprecated!\n"
                    "use self.converse.converse instead")
        return self.converse.converse(utterances, skill_id, lang, message)

    def handle_converse_error(self, message):
        """DEPRECATED: do not use, method only for api backwards compatibility
        Logs a warning
        """
        # NOTE: can not delete method for backwards compat with upstream
        LOG.warning("handle_converse_error has been deprecated!")

    def remove_active_skill(self, skill_id):
        """DEPRECATED: do not use, method only for api backwards compatibility

        Logs a warning and calls ConverseService.deactivate_skill

        Args:
            skill_id (str): skill to remove
        """
        # NOTE: can not delete method for backwards compat with upstream
        LOG.warning("self.remove_active_skill has been deprecated!\n"
                    "use self.converse.deactivate_skill instead")
        self.converse.deactivate_skill(skill_id)

    def add_active_skill(self, skill_id):
        """DEPRECATED: do not use, method only for api backwards compatibility

        Logs a warning and calls ConverseService.activate_skill

        Args:
            skill_id (str): identifier of skill to be added.
        """
        # NOTE: can not delete method for backwards compat with upstream
        LOG.warning("self.add_active_skill has been deprecated!\n"
                    "use self.converse.activate_skill instead")
        self.converse.activate_skill(skill_id)

    def send_metrics(self, intent, context, stopwatch):
        """Send timing metrics to the backend.

        NOTE: This only applies to those with Opt In.

        Args:
            intent (IntentMatch or None): intet match info
            context (dict): context info about the interaction
            stopwatch (StopWatch): Timing info about the skill parsing.
        """
        ident = context['ident'] if 'ident' in context else None
        # Determine what handled the intent
        if intent and intent.intent_service == 'Converse':
            intent_type = f'{intent.skill_id}:converse'
        elif intent and intent.intent_service == 'Fallback':
            intent_type = 'fallback'
        elif intent and intent.intent_service == 'CommonQuery':
            intent_type = 'common_qa'
        elif intent:  # Handled by an other intent parser
            # Recreate skill name from skill id
            parts = intent.intent_type.split(':')
            intent_type = self.get_skill_name(parts[0])
            if len(parts) > 1:
                intent_type = ':'.join([intent_type] + parts[1:])
        else:  # No intent was found
            intent_type = 'intent_failure'

        report_timing(ident, 'intent_service', stopwatch,
                      {'intent_type': intent_type})

    def handle_utterance(self, message):
        """Main entrypoint for handling user utterances with Mycroft skills

        Monitor the messagebus for 'recognizer_loop:utterance', typically
        generated by a spoken interaction but potentially also from a CLI
        or other method of injecting a 'user utterance' into the system.

        Utterances then work through this sequence to be handled:
        1) Active skills attempt to handle using converse()
        2) Padatious high match intents (conf > 0.95)
        3) Adapt intent handlers
        5) CommonQuery Skills
        6) High Priority Fallbacks
        7) Padatious near match intents (conf > 0.8)
        8) General Fallbacks
        9) Padatious loose match intents (conf > 0.5)
        10) Catch all fallbacks including Unknown intent handler

        If all these fail the complete_intent_failure message will be sent
        and a generic info of the failure will be spoken.

        Args:
            message (Message): The messagebus data
        """
        try:
            match, message.context, stopwatch = super().handle_utterance(message)
            self.send_metrics(match, message.context, stopwatch)
        except Exception as err:
            pass
