# coding: utf-8
from __future__ import unicode_literals

import logging
import operator
from decimal import Decimal

import yenv
from cia_stuff.oebs import utils as oebs_utils
from ids.connector import HttpConnector, plugins_lib

from cab import const
from cab.utils import auth, env, helpers


log = logging.getLogger(__name__)

HOST = env.choose({
    'production': 'review-api.yandex-team.ru',
    'testing': 'review-api.test.tools.yandex-team.ru',
    'development': '9400.localhost.yandex-team.ru',
})
NO_ACCESS = '_NO_ACCESS_'
DISABLED = '_DISABLED_'
EMPTY = '_EMPTY_'
SPECIAL_VALUES = (
    DISABLED,
    NO_ACCESS,
    EMPTY,
)


class SafeJsonResponse(plugins_lib.JsonResponse):

    def handle_response(self, response):
        try:
            return super(SafeJsonResponse, self).handle_response(response)
        except ValueError:
            log.error('Response %s is not json', response.text)
            raise


class ReviewConnector(HttpConnector):

    default_connect_timeout = 5

    available_auth_types = [
        'oauth',
        'session_id',
    ]

    if yenv.type not in ('production', 'prestable'):
        available_auth_types.append('debug-login')

    plugins = (
        auth.MultiAuthPlugin,
        SafeJsonResponse,
    )

    url_patterns = {
        'finance': '/v1/finance/',
        'bi_income_list': '/v1/bi-income-list/',
        'bi_assignments_list': '/v1/bi-assignments-list/',

        'person_reviews': '/v1/person-reviews/',
        'review_list': '/v1/reviews/?statuses=in_progress&statuses=frozen',
        'review_stats': '/v1/reviews/{id}/stats/',
    }


def _get_connector(auth):
    return ReviewConnector(
        auth=auth,
        user_agent='staff-cab',
        host=HOST,
        protocol='https',
    )


@helpers.timeit
def get_oebs_data(auth, fields, logins):
    connector = _get_connector(auth)
    data = connector.get(
        resource='finance',
        params={
            'persons': logins,
            'fields': fields,
        }
    )['result']

    data.get('musheg', {}).get('options_history', [])[:] = []  # CAB-491

    return data


@helpers.timeit
def get_person_reviews(auth, logins):
    connector = _get_connector(auth)
    data = connector.get(
        resource='person_reviews',
        params={
            'persons': logins,
        }
    )['person_reviews']
    person_reviews_by_logins = {}
    for person_review in data:
        group = person_reviews_by_logins.setdefault(person_review['person']['login'], [])
        group.append(person_review)
    return person_reviews_by_logins


def get_goldstar_value(goldstar_review_value):
    if goldstar_review_value in SPECIAL_VALUES:
        return 'no_goldstar'
    return goldstar_review_value


@helpers.timeit
def get_person_reviews_announced(auth, logins):
    person_reviews_by_logins = get_person_reviews(auth, logins)
    result = {}
    for login, person_reviews in person_reviews_by_logins.items():
        announced = [
            pr for pr in person_reviews if pr['status'] == 'announced'
        ]
        result[login] = announced
    return result


@helpers.timeit
def get_review_list(auth, **params):
    connector = _get_connector(auth)
    return connector.get(resource='review_list', params=params)


@helpers.timeit
def get_review_stats(auth, id):
    connector = _get_connector(auth)
    return connector.get(resource='review_stats', url_vars={
        'id': id,
    })


@helpers.timeit
def get_person_bi_income_list(auth, logins):
    connector = _get_connector(auth)
    return connector.post(resource='bi_income_list', params={
        'logins': ','.join(logins),
    })


@helpers.timeit
def get_person_bi_assignments_list(auth, logins):
    connector = _get_connector(auth)
    return connector.post(resource='bi_assignments_list', params={
        'logins': ','.join(logins),
    })


def merge_uniform_options(options):
    merged = {}
    for option_event in options:
        options_for_code = merged.setdefault(option_event['classCode'], {
            'amount': 0,
            'vesting': {},
        })
        vesting_for_code = options_for_code['vesting']
        options_for_code['amount'] += option_event['grantAmount']
        for vesting_event in option_event['vesting']:
            vesting_date = vesting_event['vestDate']
            vesting_amount = vesting_event['vestAmount']
            if vesting_date not in vesting_for_code:
                vesting_for_code[vesting_date] = 0
            vesting_for_code[vesting_date] += vesting_amount

    for option_data in merged.values():
        option_data['vesting'] = sorted(
            [
                {'date': vesting_date, 'amount': vesting_amount}
                for vesting_date, vesting_amount
                in option_data['vesting'].items()
            ],
            key=operator.itemgetter('date')
        )

    return merged


def merge_options_with_money(options, currency=const.RUB_CURRENCY):
    merged = {}
    if not options:
        return merged

    for grant_event in options:
        if grant_event.get('grantStatus') in ['NOT_AGREED', 'DELETED_AGREED', 'DELETED']:
            continue
        vesting_for_code = merged.setdefault(grant_event['classCode'], {})
        grant_price = Decimal(grant_event['grantPrice'] or 0)
        for vesting_event in grant_event['vesting']:
            vesting_date = vesting_event['vestDate']
            vesting_amount = vesting_event['vestAmount']
            # https://st.yandex-team.ru/STAFF-8385#1507877366000
            # в старых может приходит null в этих полях
            share_cost = Decimal(vesting_event['shareCost'] or 0)
            effecive_cost = share_cost - grant_price
            exchange_rate = Decimal(vesting_event['exchangeRate'] or 1)
            initial = {
                'amount': 0,
                'value': 0,
                'currency': currency,
            }
            vesting_for_data = vesting_for_code.setdefault(vesting_date, initial)
            vesting_for_data['amount'] += vesting_amount
            if currency == const.RUB_CURRENCY:
                vesting_for_data['value'] += vesting_amount * effecive_cost * exchange_rate
            else:
                vesting_for_data['value'] += vesting_amount * effecive_cost

    for option_class, vesting in merged.items():
        merged[option_class] = sorted(
            [
                {
                    'date': vesting_date,
                    'amount': vesting_data['amount'],
                    'value': vesting_data['value']
                }
                for vesting_date, vesting_data
                in vesting.items()
            ],
            key=operator.itemgetter('date')
        )
    return merged


class VestingValueRange(oebs_utils.VestingRange):
    value_field = 'value'
    value_wrapper = Decimal


def get_latest_salary_or_bonus_currency_change(oebs_data):
    bonus_history = oebs_data.get('bonus_history')
    salary_history = oebs_data.get('salary_history')
    dates = []
    if bonus_history:
        history = oebs_utils.BonusHistory(bonus_history)
        bonus_date = get_latest_currency_change(history)
        if bonus_date:
            dates.append(bonus_date)
    if salary_history:
        history = oebs_utils.SalaryHistory(salary_history)
        salary_date = get_latest_currency_change(history)
        if salary_date:
            dates.append(salary_date)
    if dates:
        return max(dates)


def get_latest_currency_change(history):
    prev_event = None
    for event in reversed(history):
        if event['currency'] is None:
            continue
        if prev_event and event['currency'] != prev_event['currency']:
            return history.get_date_from_item(prev_event)
        prev_event = event
