# coding: utf-8
from __future__ import unicode_literals

from logging import getLogger
from itertools import groupby
from json import dumps

from requests import Session, RequestException
from pytz import timezone, utc
from dateutil import parser

from django.conf import settings
from django.views.decorators.http import require_http_methods
from django.http import (
    HttpResponse,
    HttpResponseBadRequest,
    HttpResponseServerError,
    HttpResponseForbidden,
)

from django_yauth.decorators import yalogin_required
from django_yauth.util import get_real_ip
from ids.registry import registry
from ids import exceptions as ids_exceptions


logger = getLogger(__name__)

ISO_DATE_LEN = len('2008-09-22')


@require_http_methods(['GET'])
@yalogin_required
def commits(request):
    login = request.GET.get('login')
    page = int(request.GET.get('page', 1))

    persons = get_persons_from_staff_api(
        logins=[request.yauser.login, login],
        fields=[
            'personal.gender',
            'name.first',
            'name.last',
            'work_email',
            'official.affiliation',
        ]
    )

    if not is_internal(persons[request.yauser.login]):
        return HttpResponseForbidden()

    observer_language = request.yauser.language
    observer_tz = timezone(request.yauser.tz)

    try:
        person = get_person(persons[login], observer_language)
    except ids_exceptions.BackendError as e:
        if e.response is not None and e.response.status_code == 404:
            return HttpResponseBadRequest('Login "%s" not found' % login)
        else:
            raise

    session = Session()
    session.cookies.update(request.COOKIES)
    session.headers['X-REAL-IP'] = get_real_ip(request)

    try:
        data, page_count = get_from_dogma(session, login, page, observer_tz)
    except RequestException as e:
        logger.exception('Exception while getting commits: %s', e.message)
        return HttpResponseServerError('Error while getting commits')

    result = {
        'commits': data,
        'params': {
            'login': login,
            'page': page,
            'page_count': page_count,
        } if data else {},
        'person': person,
    }

    pg_data = get_pgindex(session, login)
    for key, value in pg_data.items():
        result[key] = value

    return HttpResponse(dumps(result), content_type='application/json; charset=utf-8')


def get_persons_from_staff_api(logins, fields):
    staff = registry.get_repository(
        'staff', 'person', user_agent='witchery', oauth_token=settings.ROBOT_OAUTH_TOKEN
    )

    fields.append('login')

    persons = staff.get(lookup={
        'login': ','.join(logins),
        '_fields': ','.join(fields),
    })

    return {
        person['login']: person
        for person in persons
    }


def is_internal(person):
    return person['official']['affiliation'] in ['yandex', 'yamoney']


def get_person(person, observer_language):
    person = {
        'first_name': person['name']['first'][observer_language],
        'last_name': person['name']['last'][observer_language],
        'work_email': person['work_email'],
        'login': person['login'],
        'gender': person['personal']['gender'].lower()[0]
    }

    inflector = registry.get_repository('inflector', 'inflector', user_agent='witchery')
    person.update(inflector.inflect_person(person, 'родительный'))
    del person['gender']
    del person['middle_name']

    return person


def get_from_dogma(session, login, page, observer_tz):
    url = (
        'https://{host}/'
        'api/v3/search/'
        'commits'
        '?q=author:{login}'
        '+exclude_dublicates:true'
        '&num_pages=true'
        '&page={page:d}'
    ).format(host=settings.DOGMA_HOST, login=login, page=page)

    data = session.get(url, timeout=5.0)
    num_pages = int(data.headers['num_pages'])
    data = data.json()

    def convert_item(item):
        parsed_date = parser.parse(item['commit']['committer']['date'])
        commit_date = utc.localize(parsed_date).astimezone(observer_tz).replace(tzinfo=None)

        result = {
            'url': item['_dogma']['html_url'],
            'branch': item['branch_name'][0],
            'stats': {
                'deletions': item['stats']['deletions'],
                'additions': item['stats']['additions'],
                'total': item['stats']['total'],
            },
            'message': item['commit']['message'],
            'issues': item['commit']['tickets'] or [],
            'date': commit_date.isoformat(),
            'author_email': item['commit']['committer']['email'],
            'repo': {
                'name': item['repo']['name'],
                'url': item['repo']['url']
            }
        }

        return result

    data = (convert_item(item) for item in data)
    data = groupby(data, lambda item: item['date'][:ISO_DATE_LEN])
    data = [(date, list(items)) for date, items in data]

    return data, num_pages


def get_pgindex(session, login):
    url = 'https://www-pgindex.n.yandex-team.ru/api/user_info/{login}'.format(login=login)
    fields = {
        'commits_count': 'commits',
        'added_lines': 'added_lines',
        'deleted_lines': 'deleted_lines',
        'weight': 'weight',
    }

    try:
        response = session.get(url, timeout=1, verify=False)
        response.raise_for_status()
    except RequestException:
        return {key: '' for key, value in fields.items()}

    data = response.json()

    try:
        data['weight'] = str(int(round(float(data['weight']))))
    except ValueError:
        pass

    return {key: data[value] for key, value in fields.items()}
