"""python functions wrapping address-to-uprn matching api calls"""

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

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

# %% ../nbs/01_api_calls.ipynb 3
class AssignAPIClient:
    """
    A client for interacting with the ASSIGN API.
    Handles environment setup and provides methods for address search, upload, and download.

    Args: 
        dotenv_path (str): Path to the .env file. Defaults to '.env'
    
    Returns:
        an instance of the AssignAPIClient class
    
    Example: 
    
        client = AssignAPIClient(dotenv_path = '.env')

    """
    
    def __init__(self, dotenv_path: str = '.env'):
        """
        Initialize the client with environment variables from the specified .env file.

        Args: 
            dotenv_path (str): Path to the .env file. Defaults to '.env'.
        """
        import os
        import requests
        from dotenv import load_dotenv
        self.ASSIGN_ENDPOINT = self._get_env_var("ASSIGN_ENDPOINT", dotenv_path)
        self.ASSIGN_USER = self._get_env_var("ASSIGN_USER", dotenv_path)
        self.ASSIGN_PASS = self._get_env_var("ASSIGN_PASS", dotenv_path)

    @staticmethod
    def _get_env_var(var_name: str, dotenv_path: str = '.env') -> str:
        """
        Get environment variable or raise an error if not found.

        Tries: 1. Existing env var; 2. a .env file; 3. Raise error.

        Args:
            var_name (str): Name of the environment variable.
            dotenv_path (str): Path to the .env file.
        
        Returns:
            str: Value of the environment variable.

        Raises:
            ValueError: If the environment variable is not found.
        """
        import os
        from dotenv import load_dotenv
        value = os.getenv(var_name)
        if value is not None:
            return value
        if dotenv_path:
            load_dotenv(dotenv_path)
            value = os.getenv(var_name)
            if value is not None:
                return value
        raise ValueError(f"Environment variable '{var_name}' not found in environment or {dotenv_path} file.")

    def address_search(self, address: str):
        """
        Search for a UPRN by address.
        
        Args: 
            address (str): An address on a single line, each element separated with a comma.
        
        Returns:
            requests.Response: JSON representation of the matching AddressBase Premium record.
        
        Example:

            > response = client.address_search('10 Downing St,Westminster,London,SW1A2AA')
            > response.json()
            {'Address_format': 'good',
            'Postcode_quality': 'good',
            'Matched': True,
            'BestMatch': {'UPRN': '100023336956',
            'Qualifier': 'Property',
            'LogicalStatus': '1',
            'Classification': 'RD04',
            'ClassTerm': 'Terraced',
            'Algorithm': '10-match1',
            'ABPAddress': {'Number': '10',
            'Street': 'Downing Street',
            'Town': 'City Of Westminster',
            'Postcode': 'SW1A 2AA'},
            'Match_pattern': {'Postcode': 'equivalent',
            'Street': 'equivalent',
            'Number': 'equivalent',
            'Building': 'equivalent',
            'Flat': 'equivalent'}}}
        """
        import requests
        response = requests.get(
            f"{self.ASSIGN_ENDPOINT}/getinfo?adrec={address}",
            auth=(self.ASSIGN_USER, self.ASSIGN_PASS)
        )
        return response

    def upload(self, infilepath: str):
        """
        Upload a text file of TSV address records to the ASSIGN API, or upload an encrypted salt.

        For address uploads, format is two columns: id and address, e.g.:

        ```tsv
        1 ⭾ 10 Downing St,Westminster,London,SW1A2AA
        2 ⭾ Bridge Street,London,SW1A 2LW
        3 ⭾ 221b Baker St,Marylebone,London,NW1 6XE
        4 ⭾ 3 Abbey Rd,St Johns Wood,London,NW8 9AY
        ```
        
        Args:
            infilepath (str): Filepath containing multiple addresses to upload.

        Returns:
            requests.Response: API response confirming whether upload was successful.
        
        Example addresses file upload:
        
            > infilepath='../data/external/test-addresses.txt'
            > client.upload(infilepath=infilepath).json()
            {'upload': {'status': 'OK'}}

        Example salt file upload (optional)

            > infilepath='../data/external/test.EncryptedSalt'
            > client.upload(infilepath=infilepath).json()
            {"upload": { "status": "SALTOK"}}
            
        """
        import os
        import requests
        url = f"{self.ASSIGN_ENDPOINT}/fileupload2"
        files = {
            "file": (os.path.basename(infilepath), open(infilepath, "rb"), "text/plain")
        }
        response = requests.post(url, files=files, auth=(self.ASSIGN_USER, self.ASSIGN_PASS))
        return response

    def download(self, infilepath: str, outfilepath: str = '../data/processed/assign-uprn.tsv'):
        """
        Download TSV data matching a previously uploaded file of TSV addresses.

        Args:
            infilepath (str): Filename of the previously uploaded file.
            outfilepath (str): Filepath to store the response in, defaults to '../data/processed/assign-uprn.tsv'

        Returns:
            requests.Response: API response containing content to output to TSV file.
        
        Example:
    
            > infilepath = '../data/external/test-addresses.txt'
            > outfilepath = '../data/processed/assign-uprn.tsv'
            > client.download(infilepath, outfilepath).status_code
            200
        """
        import os
        import requests
        url = f"{self.ASSIGN_ENDPOINT}/download3"
        params = {
            "filename": os.path.basename(infilepath),
        }
        response = requests.get(
            url, params=params, auth=(self.ASSIGN_USER, self.ASSIGN_PASS)
        )
        with open(outfilepath, "wb") as f:
            f.write(response.content)
            print(f"written to {outfilepath}")
        return response
