import boto3
from typing import Any, Union

from navalmartin_mir_aws_utils.exceptions import InvalidAWSClientException
from navalmartin_mir_aws_utils.aws_credentials import (AWSCredentials_S3, AWSCredentials_SQS, AWSCredentials_CognitoIDP,
                                                       AWSCredentials_SecretsManager)

VALID_AWS_CLIENTS = ['s3', 'sqs', "cognito-idp", "secretsmanager"]


def get_aws_client_factory(credentials: Union[AWSCredentials_S3, AWSCredentials_SQS,
                                              AWSCredentials_CognitoIDP,
                                              AWSCredentials_SecretsManager]) -> Any:
    if credentials.aws_client_name not in VALID_AWS_CLIENTS:
        raise InvalidAWSClientException(client_name=credentials.aws_client_name,
                                        allowed_vals=VALID_AWS_CLIENTS)

    if credentials.aws_client_name == 's3':
        return get_aws_s3_client(credentials=credentials)
    elif credentials.aws_client_name == 'sqs':
        return get_aws_sqs_client(credentials=credentials)
    elif credentials.aws_client_name == "cognito-idp":
        return get_aws_cognito_idp_client(credentials=credentials)
    elif credentials.aws_client_name == "secretsmanager":
        return get_aws_secrets_manager_client(credentials=credentials)

    return None


def get_aws_s3_client(credentials: AWSCredentials_S3):
    """Get the AWS S3 client

    Parameters
    ----------
    credentials: Credentials for accessing the S3 service
    Returns
    -------
    """

    if credentials.aws_region == "" or credentials.aws_region is None:
        raise ValueError("Invalid region name in credentials. "
                         "'credentials.aws_region' cannot be '' or None")

    if credentials.aws_secret_access_key is not None and credentials.aws_access_key is not None:
        return boto3.client(credentials.aws_client_name,
                            aws_access_key_id=credentials.aws_access_key,
                            aws_secret_access_key=credentials.aws_secret_access_key,
                            region_name=credentials.aws_region)

    return boto3.client(credentials.aws_client_name,
                        region_name=credentials.aws_region)


def get_aws_sqs_client(credentials: AWSCredentials_SQS):
    """Get the AWS SQS client

    Parameters
    ----------
    credentials: Credentials for accessing the SQS service

    Returns
    -------

    """

    if credentials.aws_region == "" or credentials.aws_region is None:
        raise ValueError("Invalid region name in credentials. "
                         "'credentials.aws_region' cannot be '' or None")

    if credentials.aws_secret_access_key is not None and credentials.aws_access_key is not None:
        return boto3.client(credentials.aws_client_name,
                            aws_access_key_id=credentials.aws_access_key,
                            aws_secret_access_key=credentials.aws_secret_access_key,
                            region_name=credentials.aws_region)

    return boto3.client(credentials.aws_client_name,
                        region_name=credentials.aws_region)


def get_aws_cognito_idp_client(credentials: AWSCredentials_CognitoIDP):
    """Get the Cognito IDP client for the given credentials

    Parameters
    ----------
    credentials: Credentials for accessing the Cognito IDP service

    """

    if credentials.aws_region == "" or credentials.aws_region is None:
        raise ValueError("Invalid region name in credentials. "
                         "'credentials.aws_region' cannot be '' or None")

    if credentials.aws_secret_access_key is not None and credentials.aws_access_key is not None:
        return boto3.client(credentials.aws_client_name,
                            aws_access_key_id=credentials.aws_access_key,
                            aws_secret_access_key=credentials.aws_secret_access_key,
                            region_name=credentials.aws_region)

    return boto3.client(credentials.aws_client_name, credentials.aws_region)


def get_aws_secrets_manager_client(credentials: AWSCredentials_SecretsManager) -> Any:
    """

    Parameters
    ----------
    credentials

    Returns
    -------

    """

    if credentials.aws_region == "" or credentials.aws_region is None:
        raise ValueError("Invalid region name in credentials. "
                         "'credentials.aws_region' cannot be '' or None")

    if credentials.aws_secret_access_key is not None and credentials.aws_access_key is not None:
        return boto3.client(credentials.aws_client_name,
                            aws_access_key_id=credentials.aws_access_key,
                            aws_secret_access_key=credentials.aws_secret_access_key,
                            region_name=credentials.aws_region)

    return boto3.client(credentials.aws_client_name,
                        region_name=credentials.aws_region)
