import dataclasses
import json
import logging
import typing

from tornado.httpclient import AsyncHTTPClient, HTTPRequest

LOG = logging.getLogger(__name__)


@dataclasses.dataclass
class DataService():
    '''
    Responsible for establishing a connection to a
    database through a REST API by handling authentication
    and fetching data. It utilizes the Tornado web framework
    for asynchronous HTTP requests.
    '''
    # Credentials used for authentication
    credentials: dict

    # Host URL for the CAiMIRA Data Service API
    host: str = 'https://caimira-data-api.app.cern.ch'

    # Cached access token
    _access_token: typing.Optional[str] = None

    def _is_valid(self, access_token):
        # decode access_token
        # check validity
        return False

    async def _login(self):
        if self._is_valid(self._access_token):
            return self._access_token

        # invalid access_token, fetch it again
        client_email = self.credentials["data_service_client_email"]
        client_password = self.credentials['data_service_client_password']

        if (client_email == None or client_password == None):
            # If the credentials are not defined, an exception is raised.
            raise Exception("DataService credentials not set")
            
        http_client = AsyncHTTPClient()
        headers = {'Content-type': 'application/json'}
        json_body = { "email": f"{client_email}", "password": f"{client_password}"}

        response = await http_client.fetch(HTTPRequest(
            url=self.host + '/login',
            method='POST',
            headers=headers,
            body=json.dumps(json_body),
        ),
        raise_error=True)

        self._access_token = json.loads(response.body)['access_token']
        return self._access_token

    async def fetch(self):
        access_token = await self._login()

        http_client = AsyncHTTPClient()
        headers = {'Authorization': f'Bearer {access_token}'}

        response = await http_client.fetch(HTTPRequest(
            url=self.host + '/data',
            method='GET',
            headers=headers,
        ),
        raise_error=True)

        return json.loads(response.body)
    