
# **********************************************************************
# This file has been auto-generated by a code generation tool.
# Version:   "4.1.6"
# Date/time: 25 Jul 2024 12:00:24
# Template:  /python/utilities.razor.
# **********************************************************************

# ================================================================================
# Python PWS utilities.
# ================================================================================

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

import jwt
import requests
from marshmallow import Schema
from requests import Response

from .constants import PWS_CLIENT_ID, REST_API_URI, 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(), verify= 'localhost' not in url)

    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(), verify= 'localhost' not in url)

    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, verify = 'localhost' not in url)

    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()