import aiohttp
import json
import logging

from urllib.parse import urljoin


class BackendSlot:
    _DEFAULT_REQUEST_TIMEOUT = 3

    def __init__(self, host: str, port: int) -> None:
        self._host: str = host
        self._port: int = port
        self._control_port: int = port + 3

        self._command_url: str = f'http://{self._host}:{self._control_port}'

    async def _make_request(self, path: str = '/', params: dict = None, **kwargs) -> str:
        if not kwargs.get('timeout'):
            kwargs['timeout'] = self._DEFAULT_REQUEST_TIMEOUT

        url = urljoin(self._command_url, path)
        logging.debug('Making a request to: %s', url)

        async with aiohttp.ClientSession(raise_for_status=True) as client:
            async with client.get(url, params=params, **kwargs) as response:
                response_bytes = await response.read()
                return response_bytes.decode()

    async def make_text_request(self, path: str = '/', **kwargs) -> str:
        return await self._make_request(path, **kwargs)

    async def make_json_request(self, path: str = '/', **kwargs) -> dict:
        response_text = await self._make_request(path, **kwargs)
        return json.loads(response_text)

    async def _execute_command(self, command: str, command_params: dict = None, **kwargs) -> dict:
        if command_params is None:
            command_params = {}

        params = {
            'command': command,
            **command_params
        }

        return await self.make_json_request(path='/', params=params, **kwargs)

    async def get_metrics(self) -> str:
        return await self.make_text_request(path='/metric')

    async def get_status(self) -> str:
        return await self.make_text_request(path='/status')

    async def get_tass(self) -> dict:
        return await self.make_json_request(path='/tass')

    async def enable_search(self) -> None:
        await self._execute_command('enable_search')

    async def enable_indexing(self) -> None:
        await self._execute_command('enable_indexing')

    async def disable_search(self) -> None:
        await self._execute_command('disable_search')

    async def disable_indexing(self) -> None:
        await self._execute_command('disable_indexing')
