from typing import Optional, Any, Dict, Literal

from phidata.infra.aws.api_client import AwsApiClient
from phidata.infra.aws.resource.base import AwsResource
from phidata.utils.cli_console import print_info, print_error
from phidata.utils.log import logger


class EksAddon(AwsResource):
    """
    # https://boto3.amazonaws.com/v1/documentation/api/latest/reference/services/eks.html
    """

    resource_type = "EksAddon"
    service_name = "eks"

    # Addon name
    name: str
    # EKS cluster name
    cluster_name: str
    # Addon version
    version: Optional[str] = None

    service_account_role_arn: Optional[str] = None
    resolve_conflicts: Optional[Literal["OVERWRITE", "NONE", "PRESERVE"]] = None
    client_request_token: Optional[str] = None
    tags: Optional[Dict[str, str]] = None

    preserve: Optional[bool] = False

    # provided by api on create
    created_at: Optional[str] = None
    status: Optional[str] = None

    wait_for_creation = False
    wait_for_deletion = False
    wait_for_update = False

    def _create(self, aws_client: AwsApiClient) -> bool:
        """Creates the EksAddon

        Args:
            aws_client: The AwsApiClient for the current cluster
        """
        print_info(f"Creating {self.get_resource_type()}: {self.get_resource_name()}")

        # create a dict of args which are not null, otherwise aws type validation fails
        not_null_args: Dict[str, Any] = {}
        if self.version:
            not_null_args["addonVersion"] = self.version
        if self.service_account_role_arn:
            not_null_args["serviceAccountRoleArn"] = self.service_account_role_arn
        if self.resolve_conflicts:
            not_null_args["resolveConflicts"] = self.resolve_conflicts
        if self.client_request_token:
            not_null_args["clientRequestToken"] = self.client_request_token
        if self.tags:
            not_null_args["tags"] = self.tags

        # Step 1: Create EksAddon
        service_client = self.get_service_client(aws_client)
        try:
            create_response = service_client.create_addon(
                clusterName=self.cluster_name,
                addonName=self.name,
                **not_null_args,
            )
            logger.debug(f"EksAddon: {create_response}")
            # logger.debug(f"EksAddon type: {type(create_response)}")

            # Validate Cluster creation
            self.created_at = create_response.get("addon", {}).get("createdAt", None)
            self.status = create_response.get("addon", {}).get("status", None)
            logger.debug(f"created_at: {self.created_at}")
            logger.debug(f"status: {self.status}")
            if self.created_at is not None:
                print_info(f"EksAddon created: {self.name}")
                self.active_resource = create_response
                return True
        except service_client.exceptions.ResourceInUseException:
            print_info(f"Addon already exists: {self.name}")
            return True
        except Exception as e:
            print_error(f"{self.get_resource_type()} could not be created.")
            print_error(e)
        return False

    def post_create(self, aws_client: AwsApiClient) -> bool:

        # Wait for Addon to be created
        if self.wait_for_creation:
            try:
                print_info(f"Waiting for {self.get_resource_type()} to be active.")
                waiter = self.get_service_client(aws_client).get_waiter("addon_active")
                waiter.wait(
                    clusterName=self.cluster_name,
                    addonName=self.name,
                    WaiterConfig={
                        "Delay": self.waiter_delay,
                        "MaxAttempts": self.waiter_max_attempts,
                    },
                )
            except Exception as awe:
                # print_error(f"Waiter failed: {awe}")
                pass
        return True

    def _read(self, aws_client: AwsApiClient) -> Optional[Any]:
        """Returns the EksAddon

        Args:
            aws_client: The AwsApiClient for the current cluster
        """
        from botocore.exceptions import ClientError

        logger.debug(f"Reading {self.get_resource_type()}: {self.get_resource_name()}")

        service_client = self.get_service_client(aws_client)
        try:
            describe_response = service_client.describe_addon(
                clusterName=self.cluster_name, addonName=self.name
            )
            # logger.debug(f"EksAddon: {describe_response}")
            # logger.debug(f"EksAddon type: {type(describe_response)}")
            addon_dict = describe_response.get("addon", {})

            self.created_at = addon_dict.get("createdAt", None)
            self.status = addon_dict.get("status", None)
            logger.debug(f"EksAddon created_at: {self.created_at}")
            logger.debug(f"EksAddon status: {self.status}")
            if self.created_at is not None:
                logger.debug(f"EksAddon found: {self.name}")
                self.active_resource = describe_response
        except ClientError as ce:
            logger.debug(f"ClientError: {ce}")
        except Exception as e:
            print_error(f"Error reading {self.get_resource_type()}.")
            print_error(e)
        return self.active_resource

    def _delete(self, aws_client: AwsApiClient) -> bool:
        """Deletes the EksAddon

        Args:
            aws_client: The AwsApiClient for the current cluster
        """
        print_info(f"Deleting {self.get_resource_type()}: {self.get_resource_name()}")

        # create a dict of args which are not null, otherwise aws type validation fails
        not_null_args: Dict[str, Any] = {}
        if self.preserve:
            not_null_args["preserve"] = self.preserve

        # Step 1: Delete EksAddon
        service_client = self.get_service_client(aws_client)
        self.active_resource = None
        try:
            delete_response = service_client.delete_addon(
                clusterName=self.cluster_name, addonName=self.name, **not_null_args
            )
            logger.debug(f"EksAddon: {delete_response}")
            # logger.debug(f"EksAddon type: {type(delete_response)}")
            print_info(
                f"{self.get_resource_type()}: {self.get_resource_name()} deleted"
            )
            return True
        except Exception as e:
            print_error(f"{self.get_resource_type()} could not be deleted.")
            print_error("Please try again or delete resources manually.")
            print_error(e)
        return False

    def post_delete(self, aws_client: AwsApiClient) -> bool:

        # Wait for Addon to be deleted
        if self.wait_for_deletion:
            try:
                print_info(f"Waiting for {self.get_resource_type()} to be deleted.")
                waiter = self.get_service_client(aws_client).get_waiter("addon_deleted")
                waiter.wait(
                    clusterName=self.cluster_name,
                    addonName=self.name,
                    WaiterConfig={
                        "Delay": self.waiter_delay,
                        "MaxAttempts": self.waiter_max_attempts,
                    },
                )
            except Exception as awe:
                print_error(f"Waiter failed: {awe}")
        return True
