import logging

from django.conf import settings

from staff.lib.log import log_context
from staff.lib import requests

from staff.trip_questionary.controller.operations import lib, OperationBase


logger = logging.getLogger(__name__)

edit_account_url_template = 'https://business.taxi.yandex.ru/api/1.0/client/{0}/user/'
search_account_url = 'https://business.taxi.yandex.ru/api/1.0/search/users/'

TAXI_TIMEOUT = (2, 4, 8)  # sec
TAXI_LIMIT = settings.TAXI_LIMIT
TARIFS = ['business', 'econom', 'start', 'standart', 'comfortplus', 'minivan']
AVAILABLE_COST_CENTERS = ['к аэропорту/вокзалу', 'от аэропорта/вокзала']
COST_CENTERS_FORMAT = 'select'


def _request_taxi_api(method, url, payload, oauth_token):
    try:
        response = requests.request(
            method=method,
            url=url,
            json=payload,
            timeout=TAXI_TIMEOUT,
            headers={'Authorization': oauth_token},
        )
    except requests.Timeout:
        logging.exception(
            'Yandex taxi backend timeout while '
            'querying account for person %s. method=%s',
            payload.get('email'),
            payload.get('phone'),
            method,
        )
        return None

    if response.status_code != 200:
        logger.error(
            'Yandex taxi backend responded with %s: %s',
            response.status_code,
            response.text
        )
        return None

    return response.json()


def _patch_taxi_corporate_account(phone_no, is_active, client_id, oauth_token, issue_key=None, person=None):
    payload = {
        'phone': phone_no,
        'role': {
            'classes': TARIFS,
            # лимит пока попросили убрать STAFF-8398
            # "limit": money_limit,
        },
        'is_active': is_active,
    }
    if is_active:
        payload.update({
            'email': person.work_email,
            # Это поле, заполненное ключем тикета, будет использовано для проверки, добавлен ли доступ к такси из тикета
            'nickname': issue_key,
            'fullname': '{last} {first} ({login})'.format(
                last=person.last_name,
                first=person.first_name,
                login=person.login,
            ),
            'cost_center': '',
            'cost_centers': {
                'required': True,
                'format': COST_CENTERS_FORMAT,
                'values': AVAILABLE_COST_CENTERS,
            },
        })
    url = edit_account_url_template.format(client_id)

    return _request_taxi_api('PATCH', url, payload, oauth_token)


def _check_account_activated_by_issue(issue_key, phone_no, client_id, oauth_token):
    payload = {
        'client_id': client_id,
        'user_phone': phone_no,
    }
    url = search_account_url
    search_result = _request_taxi_api('POST', url, payload, oauth_token)
    if search_result['total'] > 0:
        user_data = search_result['users'][0]
        nickname = user_data['nickname']
        if nickname == issue_key:
            return True
        else:
            logger.warning(
                'Taxi account for phone number %s nickname %s != issue_key %s',
                phone_no,
                nickname,
                issue_key,
            )
            return False
    logger.warning('Taxi account for phone number %s does not exists', phone_no)
    return False


def activate_corporate_account(issue_key, person, phone_no, client_id, oauth_token):
    return _patch_taxi_corporate_account(
        phone_no,
        is_active=True,
        issue_key=issue_key,
        person=person,
        client_id=client_id,
        oauth_token=oauth_token,
    )


def deactivate_corporate_account(issue_key, phone_no, client_id, oauth_token):
    if _check_account_activated_by_issue(issue_key, phone_no, client_id, oauth_token):
        return bool(
            _patch_taxi_corporate_account(
                phone_no,
                is_active=False,
                client_id=client_id,
                oauth_token=oauth_token,
            )
        )
    return False


class TaxiOperation(OperationBase):
    def get_employee_and_credentials(self):
        employee = self.employee_data['employee']
        chosen_assignment = self.operations_cache.get_employee_assignment(employee.login)
        if chosen_assignment:
            organization = chosen_assignment['taxUnitName']
            self.employee_data['employee_assignment'] = str(chosen_assignment['assignmentID'])
        else:
            organization = None

        if organization not in settings.TAXI_API_CREDENTIALS:
            logger.warning(
                'Unknown taxi organization %s for employee %s. Aborting operation %s.',
                organization,
                employee,
                self.name,
            )
            raise RuntimeError('unknown taxi organization %s' % organization)

        credentials = settings.TAXI_API_CREDENTIALS[organization]

        return employee, organization, credentials['client_id'], credentials['oauth_token']


@lib.register
class CreateTaxiAccount(TaxiOperation):
    def match_preconditions(self):
        return (
            not self.TC.is_conf
            and self.TC.is_between_taxi_interval
            and not self.TC.is_taxi_account_active
            and not self.TC.is_employee_canceled
        )

    def run(self):
        employee, organization, client_id, oauth_token = self.get_employee_and_credentials()
        context = {
            'employee': employee.login,
            'organization': organization,
            'operation': self.__class__.__name__,
        }
        with log_context(**context):
            activation_data = activate_corporate_account(
                issue_key=self.employee_data['trip_issue']['key'],
                person=employee,
                phone_no=self.employee_data['mobile_number_for_taxi'],
                client_id=client_id,
                oauth_token=oauth_token,
            )
        if activation_data:
            self.employee_data['taxi_account_id'] = activation_data.get('_id')
            self.employee_data['is_taxi_account_active'] = True


@lib.register
class RemoveTaxiAccount(TaxiOperation):
    def match_preconditions(self):
        return (
            self.TC.is_taxi_account_active and (
                not self.TC.is_between_taxi_interval
                or self.TC.is_conf
                or self.TC.is_employee_canceled
            )
        )

    def run(self):
        employee, organization, client_id, oauth_token = self.get_employee_and_credentials()
        context = {
            'employee': employee.login,
            'organization': organization,
            'operation': self.__class__.__name__,
        }
        with log_context(**context):
            deactivated = deactivate_corporate_account(
                issue_key=self.employee_data['trip_issue']['key'],
                phone_no=self.employee_data['mobile_number_for_taxi'],
                client_id=client_id,
                oauth_token=oauth_token,
            )
        if deactivated:
            self.employee_data['is_taxi_account_active'] = False
