#!/usr/bin/env python
# -*- coding: utf-8 -*--

# Copyright (c) 2021 Oracle and/or its affiliates.
# Licensed under the Universal Permissive License v 1.0 as shown at https://oss.oracle.com/licenses/upl/

import json
import os
from dataclasses import dataclass
from urllib.parse import urlparse

from ads.common import auth as authutil
from ads.common import oci_client as oc
from typing import Dict


class InvalidObjectStoragePath(Exception):
    """Invalid Object Storage Path."""

    pass


@dataclass
class ObjectStorageDetails:
    """ObjectStorageDetails class which contains bucket, namespace and filepath
    of a file.
    """

    bucket: str
    namespace: str
    filepath: str = ""

    def __repr__(self):
        return self.path

    @property
    def path(self):
        """Full object storage path of this file."""
        return os.path.join(
            "oci://",
            self.bucket + "@" + self.namespace,
            self.filepath.lstrip("/") if self.filepath else "",
        )

    @classmethod
    def from_path(cls, env_path: str) -> "ObjectStorageDetails":
        """Construct an ObjectStorageDetails instance from conda pack path.

        Parameters
        ----------
        env_path: (str)
            codna pack object storage path.

        Raises
        ------
        Exception: OCI conda url path not properly configured.

        Returns
        -------
        ObjectStorageDetails
            An ObjectStorageDetails instance.
        """
        try:
            url_parse = urlparse(env_path)
            bucket_name = url_parse.username
            namespace = url_parse.hostname
            object_name = url_parse.path.strip("/")
            return cls(bucket=bucket_name, namespace=namespace, filepath=object_name)
        except:
            raise Exception(
                "OCI conda url path not properly configured. "
                "It should follow this pattern `oci://<bucket-name>@<namespace>/object_path`."
            )

    def to_tuple(self):
        """Returns the values of the fields of ObjectStorageDetails class."""
        return self.bucket, self.namespace, self.filepath

    def fetch_metadata_of_object(self, auth: Dict = None) -> Dict:
        """fetch the manifest metadata from the object storage of a conda pack.

        Parameters
        ----------
        auth : Dict
            ADS auth dictionary for OCI authentication.
            This can be generated by calling ads.common.auth.api_keys() or ads.common.auth.resource_principal()
            If this is None, ads.common.default_signer(client_kwargs) will be used.

        Returns
        -------
        Dict
            metadata in dict format.
        """
        auth = auth if auth else authutil.default_signer()
        oci_client = oc.OCIClientFactory(**auth).object_storage
        res = oci_client.get_object(self.namespace, self.bucket, self.filepath)
        metadata = res.data.headers["opc-meta-manifest"]
        metadata_json = json.loads(metadata)
        return metadata_json
