from dataclasses import dataclass
from typing import Optional

from cached_property import cached_property

from saas.library.python.api_mixins import JsonAPI
from saas.library.python.sane_requests import get_session
from saas.library.python.sane_requests.exponential_retry_strategy import get_retry_strategy, DEFAULT_METHOD_WHITELIST
from saas.library.python.token_store import TokenStore


@dataclass
class WardenFunctionality:
    name: str
    slug: str
    weight: float
    target_queue: str

    description: str
    instructions: str

    test_flow: bool
    component_name: str

    def to_dict(self) -> dict:
        return {
            'name': self.name,
            'slug': self.slug,
            'description': self.description,
            'instructions': self.instructions,
            'weight': self.weight,
            'targetQueue': self.target_queue
        }


class WardenAPI(JsonAPI):

    class Subject:
        FUNCTIONALITY = 'functionality'
        COMPONENT = 'component'

    class Action:
        ADD = 'add'
        GET = 'get'
        UPDATE = 'update'
        DELETE = 'delete'

    @cached_property
    def __oauth_token(self):
        return TokenStore.get_token_from_store_or_env('warden')

    @staticmethod
    def _create_session():
        return get_session(retry_strategy=get_retry_strategy(
            method_whitelist=DEFAULT_METHOD_WHITELIST | {'POST'},
            respect_retry_after_header=False  # Retry-After: 300 seconds, seems too much
        ))

    def _make_request(
        self,
        method: str,
        endpoint: str,
        /, *,
        headers: dict = None,
        data: str = None,
        params: dict = None,
        json_params: dict = None
    ) -> any:
        headers = {**{'Authorization': f'OAuth {self.__oauth_token}'}, **(headers or {})}
        return super()._make_request(method, endpoint, headers=headers, data=data, params=params, json_params=json_params)

    @staticmethod
    def _get_endpoint(action: str, subject: str) -> str:
        return f'{action}{subject.capitalize()}'

    def add_functionality(self, functionality: WardenFunctionality) -> any:
        params = {
            'functionality': functionality.to_dict(),
            'componentName': functionality.component_name
        }
        endpoint: str = self._get_endpoint(self.Action.ADD, self.Subject.FUNCTIONALITY)
        return self._make_request('post', endpoint, json_params=params)

    def update_functionality(self, functionality_id: str, functionality: WardenFunctionality) -> any:
        params = {
            'functionality': {**functionality.to_dict(), 'id': functionality_id},
            'componentName': functionality.component_name
        }
        endpoint: str = self._get_endpoint(self.Action.UPDATE, self.Subject.FUNCTIONALITY)
        return self._make_request('post', endpoint, json_params=params)

    def delete_functionality(self, functionality_id: str):
        params = {
            'functionalityId': functionality_id
        }
        endpoint: str = self._get_endpoint(self.Action.DELETE, self.Subject.FUNCTIONALITY)
        return self._make_request('post', endpoint, json_params=params)

    def get_component(self, component_name: str) -> any:
        params = {
            'name': component_name
        }
        endpoint: str = self._get_endpoint(self.Action.GET, self.Subject.COMPONENT)
        return self._make_request('post', endpoint, json_params=params)

    @staticmethod
    def _is_error_response(response_data: any) -> bool:
        return isinstance(response_data, dict) and response_data.get('error')

    @staticmethod
    def _get_error_from_response_data(response_data) -> Optional[str]:
        return response_data.get('error')


warden_api = WardenAPI(base_url='http://warden.z.yandex-team.ru/api/warden.Warden')
