# -*- coding: utf-8 -*-
import urllib.parse

from django.conf import settings
from django.utils.encoding import force_str
from xml.etree import ElementTree

from events.common_app.utils import requests_session


CAPTCHA_URL = 'http://{0}/'.format(settings.CAPTCHA_HOSTNAME)


class Captcha(object):
    """
    About: http://wiki.yandex-team.ru/yandex-captcha/
    Docs: http://doc.yandex-team.ru/Passport/captcha/
    """
    def __init__(self, base_url=CAPTCHA_URL):
        self.base_url = base_url

    def generate(self, type='lite', checks=None):
        """Generates image and key for image
        Docs: http://doc.yandex-team.ru/Passport/captcha/concepts/api_generate.xml

        @type type: str
        @param type: captcha type. Choices:
            * 'lite' - simple captcha
            * 'std' - more complicated
            * 'rus' - russian alphabet

        @type checks: str
        @param checks: how much times this captcha could be validated

        @rtype: tuple

        Return tuple contains ('image_url', 'captcha_key'). Example:
            >> Captcha().generate()
            ('http://i.captcha.yandex.net/image?key=20YxBfPfIxoenVBy4CCWMKVzPteUES2U',
             '20YxBfPfIxoenVBy4CCWMKVzPteUES2U')
        """
        params = {
            'type': type,
        }
        if checks:
            params['checks'] = checks

        response = self._send_request_to_captcha_server('generate', params)
        if response.status_code != 200:
            return None, None

        captcha_key, attr = self._parse_response_captcha_xml(response.content)
        if attr:
            image_url = self.clean_image_url(attr.get('url', None))
        else:
            image_url = None
        return image_url, captcha_key

    def clean_image_url(self, url):
        if url.startswith('http://'):
            return 'https://' + url[7:]
        else:
            return url

    def check(self, rep, key, type='lite'):
        """Checks user input
        Docs: http://doc.yandex-team.ru/Passport/captcha/concepts/api_check.xml

        @type type: str
        @param type: captcha type. Choices:
            * 'lite' - simple captcha
            * 'std' - more complicated
            * 'rus' - russian alphabet

        @type rep: str
        @param rep: user input

        @type key: str
        @param key: captcha key

        @rtype: tuple

        Return tuple contains:
            * Boolean value - valid user input or not
            * HTTP error code

        Example:
            >> Captcha().check(type='lite', rep='hello', key='12345')
            (False, 400)

            >> Captcha().check(type='lite', rep='world', key='12345')
            (True, None)
        """
        params = {
            'type': type,
            'rep': rep,
            'key': key
        }

        response = self._send_request_to_captcha_server('check', params)

        check_result, attr = self._parse_response_captcha_xml(response.content)
        if check_result == 'ok':
            check_result = True
            response_code = None
        else:
            check_result = False
            response_code = response.status_code if response.status_code != 200 else 400

        return check_result, response_code

    def _parse_response_captcha_xml(self, xml_string):
        try:
            xml = ElementTree.XML(xml_string)
        except ElementTree.ParseError:
            return None, None

        return xml.text, xml.attrib

    def _send_request_to_captcha_server(self, method, params):
        utf_params = dict((key, force_str(value).encode('utf-8')) for key, value in params.items())
        encoded_params = urllib.parse.urlencode(utf_params)
        url = '{0}{1}?{2}'.format(self.base_url, method, encoded_params)
        return requests_session.get(url, timeout=settings.DEFAULT_TIMEOUT)
