# Copyright (C) 2020-2022 HERE Global B.V. and its affiliate(s).
# All rights reserved.
#
# This software and other materials contain proprietary information
# controlled by HERE and are protected by applicable copyright legislation.
# Any use and utilization of this software and other materials and
# disclosure to any third parties is conditional upon having a separate
# agreement with HERE for the access, use, utilization or disclosure of this
# software. In the absence of such agreement, the use of the software is not
# allowed.

"""
This module contains a :class:`ArtifactApi` class to perform Artifact API operations.
"""

from typing import Optional

from here.platform.api.base_api import BaseApi
from here.platform.auth import Auth
from here.platform.config.application_config import ApplicationConfig
from here.platform.config.platform_config import PlatformConfig
from here.platform.exceptions import PlatformException


class ArtifactApi(BaseApi):
    """
    This class provides access to HERE platform Artifact APIs.

    The artifact service provides a way to store/consume schemas and artifacts. An artifact is
    the package which can contain code, assets, binary files, and configuration data. Artifacts
    are uniquely named, versioned, and immutable. Each schema and artifact are identified by group
    ID, artifact ID and version.
    """

    def __init__(
        self,
        base_url: str,
        platform_config: PlatformConfig,
        application_config: ApplicationConfig,
        auth: Optional[Auth],
        proxies: Optional[dict] = None,
    ):
        """
        Instantiate ArtifactApi object.

        :param base_url: base url
        :param platform_config: a mandatory :class:`PlatformConfig` object to provide
        configuration information for the API.
        :param application_config: a mandatory :class:`ApplicationConfig` object to provide
        configuration information for the API.
        :param auth: an Authentication instance.
        :param proxies: an optional proxy configuration. Defaults to the environment proxy
        configuration.
        """
        super(ArtifactApi, self).__init__(
            platform_config=platform_config,
            application_config=application_config,
            auth=auth,
            proxies=proxies,
        )
        self.base_url = base_url

    def list_schemas(
        self,
        access: Optional[str] = None,
        sort: Optional[str] = None,
        order: Optional[str] = None,
        from_param: Optional[str] = None,
        group_id: Optional[str] = None,
        artifact_id: Optional[str] = None,
        limit: Optional[int] = None,
        offset: Optional[int] = None,
    ) -> dict:
        """
        Return the list of available schemas. If scoped token is used, then the list of schemas is
        returned within the project the token belongs to. If unscoped token is used, then the list
        of schemas is returned including the schemas belonging to the projects.

        :param access: Comma separated list of access types (with OR semantic) to filter result.
            If 'default', returns schema user have read access to. If 'orgAdmin', returns catalogs
            OrgAdmin user have access to.
        :param sort: sort parameter
        :param order: order of sorting
        :param from_param: from parameter
        :param group_id: Applies filtering based on groupId
        :param artifact_id: Applies filtering based on artifactId
        :param limit: limit number of records
        :param offset: offset number of records
        :return: response from the API.
        :raises PlatformException: If platform responds with an HTTP error.
        """
        path = "/schema"
        url = self.format_url(self.base_url, path)
        params = {
            "access": access,
            "sort": sort,
            "order": order,
            "from": from_param,
            "groupId": group_id,
            "artifactId": artifact_id,
            "limit": limit,
            "offset": offset,
        }
        resp = self.get(url, params=params)
        if resp.status_code == 200:
            resp_json: dict = resp.json()
            return resp_json
        else:
            raise PlatformException(resp)

    def get_schema(self, schema_hrn: str) -> dict:
        """
        Return the information about schema (hrn, groupId, artifactId, version) and related
        artifact and variants for the given HRN. If scoped token is used, then the information
        about schema is returned within the project the token belongs to.

        :param schema_hrn: The HRN of the schema.
        :return: response from the API.
        :raises PlatformException: If platform responds with an HTTP error.
        """
        path = f"/schema/{schema_hrn}"
        url = self.format_url(self.base_url, path)
        resp = self.get(url)
        if resp.status_code == 200:
            resp_json: dict = resp.json()
            return resp_json
        else:
            raise PlatformException(resp)

    def delete_schema(self, schema_hrn: str) -> dict:
        """
        Delete the schema and related artifacts by given HRN. If scoped token is used, then the
        schema is deleted within the project the token belongs to.

        :param schema_hrn: The HRN of the schema.
        :return: response from the API.
        :raises PlatformException: If platform responds with an HTTP error.
        """
        path = f"/schema/{schema_hrn}"
        url = self.format_url(self.base_url, path)
        resp = self.delete(url)
        if resp.status_code == 200:
            resp_json: dict = resp.json()
            return resp_json
        else:
            raise PlatformException(resp)

    def get_schema_document(self, schema_hrn: str, file: str) -> dict:
        """
        Return the url to schema documentation.

        :param schema_hrn: The HRN of the schema.
        :param file: The path to schema file.
        :return: response from the API.
        :raises PlatformException: If platform responds with an HTTP error.
        """
        path = f"/schema/{schema_hrn}/file/{file}"
        url = self.format_url(self.base_url, path)
        resp = self.get(url)
        if resp.status_code == 200:
            resp_json: dict = resp.json()
            return resp_json
        else:
            raise PlatformException(resp)

    def update_schema_permission(self, schema_hrn: str, body: dict) -> dict:
        """
        Grant/revoke permissions for schema. READ grants 'readResource',
        MODIFY grants 'modifyResource', SHARE grants 'shareResource'.

        :param schema_hrn: The HRN of the schema.
        :param body: a dictionary with permissions.
        :return: response from the API.
        :raises PlatformException: If platform responds with an HTTP error.
        """
        path = f"/schema/{schema_hrn}/permission"
        url = self.format_url(self.base_url, path)
        resp = self.post(url, data=body)
        if resp.status_code == 200:
            resp_json: dict = resp.json()
            return resp_json
        else:
            raise PlatformException(resp)

    def get_artifact_file(self, artifact_hrn: str, file_name: str) -> bytes:
        """
        Return the binary data of file linked to artifact.

        :param artifact_hrn: The HRN of the artifact
        :param file_name: The path to artifact file
        :return: response from the API.
        :raises PlatformException: If platform responds with an HTTP error.
        """
        path = f"/artifact/{artifact_hrn}/{file_name}"
        url = self.format_url(self.base_url, path)
        resp = self.get(url)
        if resp.status_code == 200:
            return resp.content
        else:
            raise PlatformException(resp)
