# AUTOGENERATED! DO NOT EDIT! File to edit: ../nbs/api.ipynb.

# %% auto 0
__all__ = ['ArchivematicaAPIClient']

# %% ../nbs/api.ipynb 3
import base64
import requests
import time
from requests.auth import HTTPBasicAuth
from typing import Optional

# %% ../nbs/api.ipynb 4
class ArchivematicaAPIClient(object):
    """
    A client for interacting with Matica's API for file uploading, transferring, and ingesting processes.
    """

    TIME_SPAN = 2  # Time to wait in loops, in seconds

    def __init__(self, dashboard_url: str, dashboard_username: str, dashboard_api_key: str, storage_service_url: str, storage_service_username: str, storage_service_password: str):
        """
        Initializes the ArchivematicaAPIClient with necessary details for API interactions.

        Args:
            dashboard_url (str): URL of the dashboard.
            dashboard_username (str): Username for the dashboard.
            dashboard_api_key (str): API key for the dashboard.
            storage_service_url (str): URL of the storage service.
            storage_service_username (str): Username for the storage service.
            storage_service_password (str): Password for the storage service.
        """

        self.dashbord_url = dashboard_url
        self.dashboard_username = dashboard_username
        self.dashboard_api_key = dashboard_api_key

        self.dash_board_headers = {
            'Authorization': f'ApiKey {dashboard_username}:{dashboard_api_key}',
            "Content-Type": "application/json"
        }

        self.dash_board_endpoint = f"{dashboard_url}/api"

        self.storage_service_url = storage_service_url
        self.storage_username = storage_service_username
        self.storage_password = storage_service_password
    
    def v2beta_package(self, transfer_type: str, transfer_accession: str, location_uuid: str, path: str, name: str, processing_config: str) -> str:
        """
        Initiates a file transfer process.

        Args:
            transfer_type: The type of the transfer.
            transfer_accession: The accession number for the transfer.

        Returns:
            The directory associated with the transfer.
        """

        path = f"{location_uuid}:{path}"

        path_encoded = base64.b64encode(path.encode()).decode()
        data = {
            "name": name,
            "type": transfer_type,
            "accession": transfer_accession,
            "processing_config": processing_config,
            "path": path_encoded,
        }

        response = requests.post(f'{self.dashbord_url}/api/v2beta/package/', headers=self.dash_board_headers, json=data)

        self.transfer_UUID = response.json()["id"]
        return self.transfer_UUID
    
    def approve_transfer(self, transfer_type: str, directory: str) -> str:
        """
        Approves a file transfer after initiation.

        Args:
            transfer_type (str): The type of the transfer.
            directory (str): The directory associated with the transfer.

        Returns:
            Optional[str]: The UUID of the approved transfer, if available.
        """
        while True:
            data = {"type": transfer_type, "directory": directory}
            response = requests.post(f'{self.dashbord_url}/api/transfer/approve/', headers=self.dash_board_headers, data=data)
            if "uuid" in response.json():
                self.transfer_UUID = response.json()["uuid"]
                break
            time.sleep(self.TIME_SPAN)
        return self.transfer_UUID

    def check_transfer_status(self, transfer_UUID: str) -> str:
        """
        Checks the status of a file transfer until it is no longer processing.

        Args:
            transfer_UUID: The UUID of the transfer to check.

        Returns:
            The SIP UUID of the transfer.
        """
        while True:
            response = requests.get(f'{self.dashbord_url}/api/transfer/status/{transfer_UUID}', headers=self.dash_board_headers)
            r = response.json()
            if "status" in r and r["status"] != "PROCESSING":
                self.sip_uuid = r["sip_uuid"]
                break
            time.sleep(self.TIME_SPAN)
        return self.sip_uuid

    def ingest(self, sip_UUID: str) -> str:
        """
        Waits for the ingestion process to complete and returns the UUID of the ingested AIP.

        Args:
            sip_UUID: The SIP UUID to ingest.

        Returns:
            The UUID of the ingested AIP.
        """
        while True:
            response = requests.get(f'{self.dash_board_endpoint}/ingest/status/{sip_UUID}', headers=self.dash_board_headers)
            r = response.json()
            if "status" in r and r["status"] != "PROCESSING":
                return r["uuid"]
            time.sleep(self.TIME_SPAN)

    def get_aip_url(self, ingest_UUID: str) -> str:
        """
        Constructs and returns the URL for downloading the ingested AIP.

        Args:
            ingest_UUID: The UUID of the ingested AIP.

        Returns:
            The URL for downloading the AIP.
        """
        endpoint = self.storage_service_url + "/api"
        url = f"{endpoint}/v2/file/{ingest_UUID}/download/"
        return url
    
    def get_current_full_path(self, ingest_UUID: str) -> Optional[str]:
        """
        Retrieves the current full path of the ingested AIP by making an API call.

        Args:
            ingest_UUID (str): The UUID of the ingested AIP.

        Returns:
            Optional[str]: The current full path of the AIP if the request is successful, None otherwise.
        """
        endpoint = self.storage_service_url + "/api"
        url = f"{endpoint}/v2/file/{ingest_UUID}/"

        try:
            response = requests.get(url, auth=HTTPBasicAuth(self.storage_username, self.storage_password))
            response.raise_for_status()  # Raises an exception for 4XX or 5XX errors
            return response.json().get("current_full_path")
        except requests.RequestException as e:
            print(f"Error retrieving current full path: {e}")
            return None

