import re

from .utils import OrderedDict, YAMLLoaderMixin


class YAMLDocstringParser(YAMLLoaderMixin):
    """
    YAML docstring parser
    """

    def __init__(self, docstring=''):
        self.doc = docstring or ''

        self.summary, self.description, self.schema = self._parse_docstring(self.doc)

    def _parse_docstring(self, docstring=''):
        """
        :param docstring:
        :return: (summary, description, schema)
        """
        summary, description, schema = None, None, dict()
        docstring = docstring.strip()

        if '---' in docstring:
            head, yml = re.split(r'\s*---+\s*\n', docstring)
            if yml:
                schema = self.yaml_load(yml) or dict()
        else:
            head = docstring

        if '\n' in head.strip():
            summary, description = map(lambda s: s.strip(), head.split('\n', 1))
        elif head:
            summary = head.strip()

        return summary, description, schema

    def get_description(self):
        """
        :return: Description found in docstring
        :rtype: str
        """
        return self.description

    def get_summary(self):
        """
        :return: Summary found in docstring
        :rtype: str
        """
        return self.summary

    def get_tags(self):
        """
        :return: Tags found in docstring
        :rtype: list
        """
        return self.schema.get('tags', list())

    def get_parameters(self):
        """
        :return: Parameters found in docstring
        :rtype: list
        """
        return self.schema.get('parameters', list())

    def get_responses(self):
        """
        :return: Responses found in docstring
        :rtype: dict
        """
        return self.schema.get('responses', dict())

    def get_serializer(self, request=False):
        """
        Get serializer found in docstring

        :param request: is request serializer?
        :return: Serializer path
        :rtype: str
        """
        serializer = None
        serializers = self.schema.get('serializers', None)
        serializer_type = 'request' if request else 'response'
        if serializers:
            raw = serializers.get(serializer_type, dict())
            serializer = raw.get('path', None)
        return serializer

    def get_serializers(self):
        """
        Get all serializers found in docstring

        :return: list of serializers path
        :rtype: list
        """
        serializers = []
        for key, value in self.schema.get('serializers', dict()).items():
            path = value.get('path', None)
            if path:
                serializers.append(path)
        return serializers

    def get_response_serializer(self):
        """
        Get response serializer found in docstring

        :return: Serializer path
        :rtype: str
        """
        return self.get_serializer()

    def get_request_serializer(self):
        """
        Get request serializer found in docstring

        :return: Serializer path
        :rtype: str
        """
        return self.get_serializer(request=True)

    def get_security(self):
        """
        :return: Parameters found in docstring
        :rtype: list
        """
        return self.schema.get('security', list())

    def get_security_definitions(self):
        """
        :return: Responses found in docstring
        :rtype: dict
        """
        return self.schema.get('securityDefinitions', dict())

    def update(self, docstring=''):
        """
        Update parser with another docstring
        :param docstring:
        """
        if docstring is None:
            docstring = ''
        summary, description, schema = self._parse_docstring(docstring)

        # update summary
        self.summary = summary or self.summary
        # update description
        self.description = description or self.description

        # update schema
        for k, v in schema.items():
            if k not in self.schema:
                self.schema[k] = v
            else:
                if isinstance(v, list):
                    self.schema[k].extend(v)
                elif isinstance(v, (dict, OrderedDict)):
                    self.schema[k].update(v)