# -*- coding: utf-8 -*-
from fastapi import Request
from typing import Dict

from .blackbox import InternalBlackbox, ExternalBlackbox
from .conf import AppTypeSettings
from .http import get_async_tvm2_client
from .types import AppTypes
from .utils import get_instance_ip


class BaseAuth:
    def get_headers(self, request: Request) -> Dict[bytes, bytes]:
        return dict(request.scope.get('headers') or ())

    def get_settings(self, request: Request) -> AppTypeSettings:
        return request.scope['settings']

    async def auth(self, request: Request):
        raise NotImplementedError


class SessionCookieAuth(BaseAuth):
    cookie_name = 'Session_id'

    def get_cookies(self, headers: Dict[bytes, bytes]):
        cookies = {}
        for cookie in headers.get(b'cookie', b'').decode().split(';'):
            name, *value = cookie.strip().split('=', 1)
            if not name or len(value) == 0:
                continue
            cookies[name] = value[0]
        return cookies

    def get_session_id(self, headers: Dict[bytes, bytes]) -> str:
        cookies = self.get_cookies(headers)
        return cookies.get(self.cookie_name)

    def get_user_ip(self, headers: Dict[bytes, bytes]) -> str:
        user_ip = headers.get(b'x-real-ip', b'').decode()
        if not user_ip:
            user_ip = get_instance_ip()
        return user_ip

    def get_blackbox(self, settings: AppTypeSettings):
        if settings.app_type == AppTypes.forms_biz:
            return ExternalBlackbox(settings, settings.blackbox_name)
        return InternalBlackbox(settings)

    async def auth(self, request: Request):
        from .user import YandexUser
        settings = self.get_settings(request)
        headers = self.get_headers(request)
        session_id = self.get_session_id(headers)
        if session_id:
            blackbox = self.get_blackbox(settings)
            user_ip = self.get_user_ip(headers)
            user_uid = await blackbox.sessionid(session_id, user_ip)
            if user_uid:
                return YandexUser(uid=user_uid)


class TvmServiceAuth(BaseAuth):
    service_ticket_name = b'x-ya-service-ticket'
    user_uid_name = b'x-uid'

    def get_service_ticket(self, headers: Dict[bytes, bytes]) -> str:
        return headers.get(self.service_ticket_name, b'').decode()

    def get_user_uid(self, headers: Dict[bytes, bytes]) -> str:
        return headers.get(self.user_uid_name, b'').decode()

    async def auth(self, request: Request):
        from .user import ServiceUser
        settings = self.get_settings(request)
        headers = self.get_headers(request)
        service_ticket = self.get_service_ticket(headers)
        user_uid = self.get_user_uid(headers)
        if service_ticket and user_uid:
            client = get_async_tvm2_client(settings)
            response = await client.parse_service_ticket(service_ticket)
            if response:
                return ServiceUser(src=response.src, uid=user_uid)
