
# **********************************************************************
# This file has been auto-generated by a code generation tool.
# Version:   4.2.0
# Date/time: 22 Nov 2024 12:56:19
# Template:  templates/pythonpws/utilities.razor.
# **********************************************************************

import sys, os, json, pathlib, jwt
from typing import Tuple
import datetime
import re

import requests
from requests import Response
from marshmallow import Schema

from .constants import REST_API_URI, PWS_CLIENT_ID, REST_API_VERSION

def get_data_directory() -> pathlib.Path:
    """
    Returns a parent directory path where persistent application data can be stored.

    Parameters
    ----------
    None

    Returns
    -------
    pathlib.Path: The path to the parent directory where persistent application data can be stored.
        linux: ~/.local/share
        macOS: ~/Library/Application Support
        windows: C:/Users/<USER>/AppData/Roaming
    """

    home = pathlib.Path.home()

    if sys.platform == "win32":
        return home / "AppData/Roaming"
    elif sys.platform == "linux2":
        return home / ".local/share"
    elif sys.platform == "linux":
        return home / ".local/share"
    elif sys.platform == "darwin":
        return home / "Library/Application Support"

def get_headers():
    """Get the headers."""

    return {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {get_access_token()}'
    }

# Post json to url and time the call
def post_request(url, data) -> Response:
    """
    Post to the specified data to the specified url.

    Parameters
    ----------
    url : str
        The url to post to.
    data :
        The data to post.

    Returns
    -------
    The response.
    """

    response = requests.post(url, data=data, headers=get_headers())

    return response

# Post json to url and time the call
def put_request(url, data) -> Response:
    """
    Put to the specified data to the specified url.

    Parameters
    ----------
    url : str
        The url to put to.
    data :
        The data to put.

    Returns
    -------
    The response.
    """

    response = requests.put(url, data=data, headers=get_headers())

    return response

def get_request(url) -> Response:
    """
    Get data from the specified url.

    Parameters
    ----------
    url : str
        The url to get data from.

    Returns
    -------
    The response.
    """

    headers = {
        'Content-Type': 'application/json',
        'Authorization': f'Bearer {get_access_token()}'
    }

    response = requests.get(url, headers = headers)

    return response

def get_access_token():
    """
    Get the access token from the PWS_ACCESS_TOKEN environment variable.
    If the PWS_ACCESS_TOKEN environment variable is not set, then look for the PYPWS_ACCESS_TOKEN environment variable.
    If the PYPWS_ACCESS_TOKEN environment variable is set, then set the PWS_ACCESS_TOKEN environment variable to the value of the PYPWS_ACCESS_TOKEN environment variable.

    Parameters
    ----------
    None

    Returns
    -------
    The access token.
    """

    debug = os.getenv('PYPWS_DEBUG')
    access_token = os.getenv('PWS_ACCESS_TOKEN')

    if not access_token:
        access_token = os.getenv('PYPWS_ACCESS_TOKEN')
        if access_token:
            os.environ['PWS_ACCESS_TOKEN'] = access_token
            os.environ['PYPWS_ACCESS_TOKEN'] = ''

    if debug and access_token:
        print('Found access token in environment variable.')
        platform, expiry_date, has_expired = get_access_token_info(access_token)
        print(f"Platform: {platform}. Expiry date: {expiry_date}. Expired: {has_expired}")

    if not access_token:
        print('Access token not found.  Please define an environment variable called PWS_ACCESS_TOKEN and set its value to your access token (downloaded from the Plant Web Services web site).')

    return access_token

def get_access_token_info(access_token: str) -> Tuple[str, datetime.datetime, bool]:
    """
    Get the platform, expiry date and whether the access token has expired.

    Parameters
    ----------
    access_token : str
        The access token.

    Returns
    -------
    (platform, expiry_date, has_expired)
    """

    decoded = jwt.decode(access_token, options={"verify_signature": False})
    platform = decoded['aud']
    expiry_date = datetime.datetime.fromtimestamp(decoded['exp'])
    has_expired = expiry_date < datetime.datetime.now()

    return (platform, expiry_date, has_expired)

def get_api_root() -> str:
    """
    Get the API root.
    """

    access_token = get_access_token()

    if access_token:

        (platform, _, _) = get_access_token_info(access_token)

        api_target = f"{platform}/api/"

        if api_target:
            return api_target

        return REST_API_URI

def get_api_version() -> str:
    """
    Get the API version.
    """

    api_version = os.getenv('PYPWS_API_VERSION')

    if api_version:
        return api_version

    return REST_API_VERSION

def get_analytics_api_target() -> str:
    """
    Get the analytics API target.
    """

    analytics_api_root = f'{get_api_root()}analytics/v{get_api_version()}/'

    return analytics_api_root

def get_materials_api_target() -> str:
    """
    Get the materials API target.
    """

    materials_api_root = f'{get_api_root()}materials-storage/v{get_api_version()}/'

    return materials_api_root

def get_client_alias_id() -> str:
    """
    Get the client alias id.
    """

    clientAliasId = os.getenv('PYPWS_CLIENT_ALIAS_ID')

    if clientAliasId:
        return clientAliasId

    return PWS_CLIENT_ID


def convert_snake_case_to_camel_case(snake_str):
    """
    Returns a string as camelCase.

    Parameters
    ----------
    snake_str : str
        The snake_case string.

    Returns
    -------
    The camelCase string.
    """

    components = snake_str.split('_')
    return components[0] + ''.join(x.title() for x in components[1:])

def convert_camel_case_to_snake_case(camel_str):
    """
    Returns a string as snake_case.

    Parameters
    ----------
    camel_str : str
        The camelCase string.

    Returns
    -------
    The snake_case string.
    """

    return re.sub(r'(?<^)(?=[A-Z])', '_', camel_str).lower()