"""
License:
This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0.
If a copy of the MPL was not distributed with this file, You can obtain one at https://mozilla.org/MPL/2.0/.
"""

import json
import os
import time
from hub import config
from hub.client.base import HubHttpClient
from hub.client.auth import AuthClient
from pathlib import Path
from hub import defaults
from hub.exceptions import NotFoundException
from hub.log import logger
import traceback


class HubControlClient(HubHttpClient):
    """
    Controlling Hub through rest api
    """

    def __init__(self):
        super().__init__()
        self.details = self.get_config()

    def get_dataset_path(self, tag):
        try:
            dataset = self.request(
                "GET",
                config.GET_DATASET_PATH_SUFFIX,
                params={"tag": tag},
                endpoint=config.HUB_REST_ENDPOINT,
            ).json()

        except NotFoundException:
            dataset = None
        return dataset

    def get_credentials(self):
        if self.auth_header is None:
            token = AuthClient().get_access_token(username="public", password="")
            self.auth_header = f"Bearer {token}"

        r = self.request(
            "GET",
            config.GET_CREDENTIALS_SUFFIX,
            endpoint=config.HUB_REST_ENDPOINT,
            params={"duration": defaults.CRED_EXPIRATION},
        ).json()

        details = {
            "_id": r["_id"],
            "region": r["region"],
            "session_token": r["session_token"],
            "access_key": r["access_key"],
            "secret_key": r["secret_key"],
            "endpoint": r["endpoint"],
            "expiration": r["expiration"],
            "bucket": r["bucket"],
        }

        self.save_config(details)
        return details

    def get_dataset_credentials(self, org_id, ds_name):
        self.auth_header = (
            self.auth_header
            if self.auth_header is not None
            else f'Bearer {AuthClient().get_access_token(username="public", password="")}'
        )
        relative_url = config.GET_DATASET_CREDENTIALS_SUFFIX % (org_id, ds_name)
        r = self.request(
            "GET",
            relative_url,
            endpoint=config.HUB_REST_ENDPOINT,
        ).json()
        return r["creds"], r["path"]

    def get_config(self, reset=False):
        if not os.path.isfile(config.STORE_CONFIG_PATH) or self.auth_header is None:
            self.get_credentials()

        with open(config.STORE_CONFIG_PATH) as file:
            details = file.readlines()
            details = json.loads("".join(details))
        if float(details["expiration"]) < time.time() or reset:
            details = self.get_credentials()
        return details

    def save_config(self, details):
        path = Path(config.STORE_CONFIG_PATH)
        os.makedirs(path.parent, exist_ok=True)
        with open(config.STORE_CONFIG_PATH, "w") as file:
            file.writelines(json.dumps(details))

    def create_dataset_entry(self, username, dataset_name, meta, public=True):
        try:
            tag = f"{username}/{dataset_name}"
            repo = f"public/{username}" if public else f"private/{username}"

            response = self.request(
                "POST",
                config.CREATE_DATASET_SUFFIX,
                json={
                    "tag": tag,
                    "repository": repo,
                    "public": public,
                    "rewrite": True,
                },
                endpoint=config.HUB_REST_ENDPOINT,
            )

            if response.status_code == 200:
                logger.info(
                    f"Your dataset is available at {config.HUB_REST_ENDPOINT}/datasets/explore?tag={tag}"
                )
                if public is False:
                    logger.info(
                        "The dataset is private so make sure you are logged in!"
                    )
        except Exception as e:
            logger.error(
                "Unable to create Dataset entry" + traceback.format_exc() + str(e)
            )

    def update_dataset_state(self, username, dataset_name, state, progress=0):
        try:
            tag = f"{username}/{dataset_name}"
            self.request(
                "POST",
                config.UPDATE_STATE_SUFFIX,
                json={
                    "tag": tag,
                    "state": state,
                    "progress": progress,
                },
                endpoint=config.HUB_REST_ENDPOINT,
            ).json()
        except Exception as e:
            logger.error(
                "Unable to update Dataset entry state "
                + traceback.format_exc()
                + str(e)
            )

    def delete_dataset_entry(self, username, dataset_name):
        try:
            tag = f"{username}/{dataset_name}"
            suffix = f"{config.DATASET_SUFFIX}/{tag}"
            self.request(
                "DELETE",
                suffix,
                endpoint=config.HUB_REST_ENDPOINT,
            ).json()
        except Exception as e:
            logger.error(
                "Unable to delete Dataset entry" + traceback.format_exc() + str(e)
            )
