# -*- coding: utf-8 -*-

import hashlib
import logging
import json

import rtyserver_pb2 as rtyserver
import utils
import multipart


LOG = logging.getLogger('suggest.message')


class SuggestMessage(object):
    def __init__(self, keyprefix, text, query, send_type, timestamp, emails=()):
        """
        keyprefix: int
        text: unicode
        query: dict
        send_type: str
        timestamp: int
        """
        self.keyprefix = keyprefix
        self.text = text
        self.query = query
        self.send_type = send_type
        self.timestamp = timestamp
        self.emails = emails

        """
        Поскольку формат запроса часто меняется, а пользователи регулярно кочуют между
        базами, при формировании урла нужно учитывать только suid пользователя и текст
        запроса. В противном случае возникают дубли.
        https://jira.yandex-team.ru/browse/DARIA-13081
        Для url документа и тела используется запрос в нижнем регистре
        """
        self.ltext = text.lower()
        self.url = hashlib.md5('%s %s' % (self.ltext.encode('utf-8'), self.keyprefix)).hexdigest()
        if self.send_type != 'delete':
            self.body = 'someqtrnvhkly ' + self.ltext
        else:
            self.body = ''

    def __hash__(self):
        return int(hashlib.md5('.'.join(8 * ('%s',)) % \
            (self.keyprefix, self.text, sorted(self.query.items()), self.send_type,
            self.timestamp, self.ltext, self.url, self.body)).hexdigest(), 16)

    def __eq__(self, other):
        if isinstance(other, SuggestMessage):
            if self.__hash__() == other.__hash__():
                return True
        return False

    def __str__(self):
        return 'keyprefix %s, url %s, text %s, type %s, orig %s, timestamp %s' % \
            (self.keyprefix, self.url, self.body, self.send_type, self.text, self.timestamp)

    def get_user_db(self):
        return self.query.get('db')

    def create_proto_message(self, with_response=True):
        message = rtyserver.TMessage()
        if with_response:
            message.MessageId = utils.MESSAGE_ID
        message.MessageType = utils.SEND_TYPES.get(self.send_type)

        document = message.Document
        document.Url = self.url

        document.MimeType = 'text/plain'
        document.Charset = 'utf-8'
        document.KeyPrefix = self.keyprefix
        if self.send_type == 'delete':
            return utils.encode_varint(message.ByteSize()) + message.SerializeToString()

        if self.send_type != 'delete':
            document.Body = self.body

        proto_attr = document.GroupAttributes.add()
        proto_attr.Name = 'req_timestamp'
        proto_attr.Value = str(self.timestamp)
        proto_attr.Type = rtyserver.TMessage.TDocument.TAttribute.INTEGER_ATTRIBUTE

        for key, value in self.query.items():
            property = document.DocumentProperties.add()
            property.Name = key

            try:
                value = unicode(value, 'utf-8')
            except UnicodeDecodeError:
                LOG.warn('bad str %s, value %r', (self.keyprefix, self.url), value)
            property.Value = value

        # https://jira.yandex-team.ru/browse/DARIA-13081
        # в properties текст запроса в оригинальном регистре
        prop_orig_text = document.DocumentProperties.add()
        prop_orig_text.Name = "orig_text"
        prop_orig_text.Value = self.text

        if len(self.emails) == 0:
            # https://jira.yandex-team.ru/browse/DARIA-13081
            # в поисковых атрибутах текст запроса в нижнем регистре
            search_attr = document.SearchAttributes.add()
            search_attr.Name = 'orig_text'
            search_attr.Value = self.ltext
            search_attr.Type = rtyserver.TMessage.TDocument.TAttribute.LITERAL_ATTRIBUTE

        for email in self.emails:
            em_attr = document.SearchAttributes.add()
            em_attr.Name = 's_email'
            em_attr.Value = email
            em_attr.Type = rtyserver.TMessage.TDocument.TAttribute.LITERAL_ATTRIBUTE

        return utils.encode_varint(message.ByteSize()) + message.SerializeToString()

    def create_http_request_body_headers(self):
        attr_arr = [{'name': '%s' % k, 'value': '%s' % v} for k, v in self.query.items()]
        attr_arr.append({'name': 'orig_text', 'value': self.text})
        group_attr = [{'name': 'req_timestamp', 'value': self.timestamp, 'type': 'integer'}]
        search_attr = []
        if len(self.emails) == 0:
            search_attr = [{'name': 'orig_text', 'value': self.ltext, 'type': 'literal'}]
        for email in self.emails:
            search_attr.append({'name': 's_email', 'value': email, 'type' : 'literal'})
        if self.send_type == 'delete':
            json_message = json.dumps({
                'send_type': self.send_type,
                'url': self.url,
                'mime_type': 'text/plain',
                'charset': 'utf8',
                'keyprefix': self.keyprefix,
            })
        else:
            json_message = json.dumps({
                'send_type': self.send_type,
                'url': self.url,
                'mime_type': 'text/plain',
                'charset': 'utf8',
                'document_attributes': attr_arr,
                'grouping_attributes': group_attr,
                'search_attributes': search_attr,
                'keyprefix': self.keyprefix,
            })

        if self.send_type == 'delete':
            return multipart.encode({'json_message': json_message}, {})
        else:
            return multipart.encode({'json_message': json_message, 'document': self.body}, {})
