import functools
import os
import logging
import aiohttp
from typing import Dict, Optional, Union

from tvm2 import TVM2
# from tvmauth import BlackboxTvmId as BlackboxClientId
from tvm2.protocol import BlackboxClientId
from django.conf import settings
from django.http import HttpRequest

from staff.lib import requests

logger = logging.getLogger(__name__)


GET_TICKET_TIMEOUT = 0.3
AUTH_HEADERS = {'Authorization': os.getenv(str('TVMTOOL_LOCAL_AUTHTOKEN'), '')}
TVM_LOCAL_ADDRESS_TICKETS = os.getenv(str('DEPLOY_TVM_TOOL_URL'), '') + "/tvm/tickets"
TVM_SERVICE_TICKET_HEADER = 'X-Ya-Service-Ticket'
TVM_USER_TICKET_HEADER = 'X-Ya-User-Ticket'

tvm2_deploy_session = requests.Session()
tvm2_deploy_session.headers.update(AUTH_HEADERS)


def get_tvm_client() -> TVM2:
    return TVM2(
        client_id=settings.YAUTH_TVM2_CLIENT_ID,
        blackbox_client=BlackboxClientId.ProdYateam,
        allowed_clients=settings.YAUTH_TVM2_ALLOWED_CLIENT_IDS,
    )


def get_user_ticket(
        session_id: str = None,
        oauth_token: str = None,
        user_ip: str = None,
        server_host: str = None) -> str:

    user_ip = user_ip or '127.0.0.1'
    server_host = server_host or 'staff.yandex-team.ru'
    return get_tvm_client().get_user_ticket(
        user_ip=user_ip,
        server_host=server_host,
        oauth_token=oauth_token,
        session_id=session_id,
    )


def get_user_ticket_for_robot_staff() -> str:
    return get_user_ticket(oauth_token=settings.ROBOT_STAFF_OAUTH_TOKEN)


def get_tvm_ticket_by_deploy(service_name: str, server_id: Union[int, str] = None) -> str:
    if server_id is None:
        server_id = service_name
    response = tvm2_deploy_session.get(
        url=TVM_LOCAL_ADDRESS_TICKETS,
        params={'dsts': server_id, 'src': settings.YAUTH_TVM2_CLIENT_ID},
        timeout=GET_TICKET_TIMEOUT,
    )
    response.raise_for_status()
    json_response = response.json()
    ticket = json_response[service_name]['ticket']
    return ticket


def get_user_ticket_for_reqeust(request: HttpRequest) -> str:
    server_host = request.META.get('HTTP_X_FORWARDED_HOST')
    user_ip = request.META.get('HTTP_X_REAL_IP')
    user_ticket = get_user_ticket(
        session_id=request.COOKIES.get('Session_id'),
        server_host=server_host,
        user_ip=user_ip,
    )
    return user_ticket


def get_tvm_headers_for_requests(
    request: HttpRequest,
    target_service: str,
) -> Dict[str, str]:
    user_ticket = (
        request.META.get('HTTP_X_YA_USER_TICKET')
        or get_user_ticket_for_reqeust(request)
    )
    service_ticket = get_tvm_ticket_by_deploy(target_service)
    return {
        TVM_SERVICE_TICKET_HEADER: service_ticket,
        TVM_USER_TICKET_HEADER: user_ticket,
    }


def get_calling_service_name(request: HttpRequest) -> Optional[str]:
    try:
        tvm_id = request.yauser.service_ticket.src
    except AttributeError:
        return
    return _get_tvm_name_by_id(tvm_id)


@functools.lru_cache(None)
def _get_tvm_name_by_id(tvm_id: int) -> Optional[str]:
    for name, id_ in settings.TVM_APPLICATIONS.items():
        if id_ == tvm_id:
            return name


async def async_get_tvm_ticket(name: str, server_id: Union[int, str] = None):
    if server_id is None:
        server_id = name
    params = {'dsts': server_id, 'src': settings.YAUTH_TVM2_CLIENT_ID}
    timeout = aiohttp.ClientTimeout(total=GET_TICKET_TIMEOUT)
    session = aiohttp.ClientSession(headers=AUTH_HEADERS, timeout=timeout)
    async with session:
        async with session.get(url=TVM_LOCAL_ADDRESS_TICKETS, params=params) as response:
            json_response = await response.json()
            return json_response[name]['ticket']
