import boto3
from botocore.exceptions import NoCredentialsError, PartialCredentialsError

class AWSConnector:
    """
    Handles the connection to AWS.

    This class provides a singleton pattern for the boto3 session, ensuring that
    only one session is created and used throughout the application. This is crucial
    for performance and managing credentials consistently.
    """
    _session = None
    _account_id = None

    @classmethod
    def get_session(cls):
        """
        Gets the boto3 session.

        If a session does not already exist, it creates one. It uses the default
        credential resolution chain provided by boto3 (environment variables,
        shared credential file, etc.).

        Returns:
            boto3.Session: The active boto3 session.
        
        Raises:
            NoCredentialsError: If AWS credentials are not found.
            PartialCredentialsError: If incomplete AWS credentials are found.
        """
        if cls._session is None:
            try:
                print("Creating new AWS session...")
                cls._session = boto3.Session()
                # Test credentials and get account ID
                cls.get_account_id()
                print("AWS session created successfully.")
            except (NoCredentialsError, PartialCredentialsError) as e:
                print(f"Error: AWS credentials not configured properly. {e}")
                print("Please configure your AWS credentials (e.g., via `aws configure` or environment variables).")
                raise
        return cls._session

    @classmethod
    def get_account_id(cls):
        """
        Gets the AWS Account ID from the current session.

        Caches the account ID after the first call.

        Returns:
            str: The AWS Account ID.
        """
        if cls._account_id is None:
            print("Fetching AWS Account ID...")
            sts_client = cls.get_session().client('sts')
            response = sts_client.get_caller_identity()
            cls._account_id = response['Account']
        return cls._account_id

    @classmethod
    def get_client(cls, service_name, region_name=None):
        """
        Gets a boto3 client for a specific AWS service.

        Args:
            service_name (str): The name of the AWS service (e.g., 'ec2', 's3').
            region_name (str, optional): The AWS region. Defaults to None, which
                                         typically uses the default region from the config.

        Returns:
            boto3.client: A client for the specified service.
        """
        session = cls.get_session()
        return session.client(service_name, region_name=region_name)

    @classmethod
    def get_resource(cls, service_name, region_name=None):
        """
        Gets a boto3 resource for a specific AWS service.

        Args:
            service_name (str): The name of the AWS service (e.g., 'ec2', 's3').
            region_name (str, optional): The AWS region. Defaults to None.

        Returns:
            boto3.resource: A resource object for the specified service.
        """
        session = cls.get_session()
        return session.resource(service_name, region_name=region_name)

    @classmethod
    def login(cls):
        """
        Attempts to log in to AWS by verifying credentials.
        """
        try:
            cls.get_session()
            print("Successfully verified AWS credentials.")
            return True
        except (NoCredentialsError, PartialCredentialsError):
            print("AWS credentials not found or are incomplete. Please configure your AWS CLI or environment variables.")
            return False
        except Exception as e:
            print(f"An unexpected error occurred during AWS login: {e}")
            return False
