import click
import boto3
import json
import os
import yaml
import time
import pathlib
from typing import Optional, TYPE_CHECKING
from .pipeline import InfraPipeline
from .features.infra.infra_feature import InfraFeature

if TYPE_CHECKING:
    from mypy_boto3_cloudformation import CloudFormationClient

# Helper function to validate CloudFormation template
def validate_template(template_body: str, cloudformation_client: 'CloudFormationClient') -> tuple[bool, str]:
    """
    Validate a CloudFormation template using AWS CloudFormation service.
    
    Args:
        template_body: The CloudFormation template as a JSON string
        cloudformation_client: Boto3 CloudFormation client
        
    Returns:
        Tuple of (is_valid: bool, message: str)
    """
    try:
        response = cloudformation_client.validate_template(TemplateBody=template_body)
        return True, f"Template is valid. Description: {response.get('Description', 'No description')}"
    except Exception as e:
        # CloudFormation validation errors come as ClientError exceptions
        return False, f"Template validation failed: {e}"

# Helper function to assume role and get client
def get_aws_client(service_name: str, deploy_role_arn: Optional[str] = None) -> 'CloudFormationClient':
    if deploy_role_arn:
        sts_client = boto3.client('sts')
        try:
            assumed_role_object = sts_client.assume_role(
                RoleArn=deploy_role_arn,
                RoleSessionName="IICYDeploymentSession"
            )
            credentials = assumed_role_object['Credentials']
            return boto3.client(
                service_name,
                aws_access_key_id=credentials['AccessKeyId'],
                aws_secret_access_key=credentials['SecretAccessKey'],
                aws_session_token=credentials['SessionToken'],
            )
        except Exception as e:
            raise click.ClickException(f"Failed to assume role {deploy_role_arn}: {e}")
    else:
        return boto3.client(service_name)


@click.group()
def cli():
    """A CLI for iicy project."""
    pass

@cli.command()
@click.argument('path', type=click.Path(exists=True, file_okay=True, dir_okay=True), required=False, default='.')
@click.option('--stacks', '-s', multiple=True, 
              help='Specific stack names to analyze. If not provided, analyzes all stacks.')
@click.option('--output-dir', '-o', default='iicy.out', 
              help='Output directory for CloudFormation templates (defaults to iicy.out).')
def analyze(path, stacks, output_dir):
    """
    Analyzes Python code for iicy constructs and generates CloudFormation templates.
    Templates are saved to separate files in the output directory, one per stack.
    
    If no path is provided, analyzes the current working directory.
    """
    # Generate stack templates using pipeline
    pipeline = InfraPipeline()
    stack_templates = pipeline.generate(path)
    
    # Filter stacks if specific stacks are requested
    if stacks:
        # Convert to set for efficient lookup
        requested_stacks = set(stacks)
        available_stacks = set(stack_templates.keys())
        
        # Check if all requested stacks exist
        missing_stacks = requested_stacks - available_stacks
        if missing_stacks:
            click.echo(f"Error: Requested stacks not found: {', '.join(missing_stacks)}", err=True)
            click.echo(f"Available stacks: {', '.join(available_stacks)}", err=True)
            return
        
        # Filter stack templates to only include requested stacks
        stack_templates = {name: template for name, template in stack_templates.items() if name in requested_stacks}
        click.echo(f"Analyzing stacks: {', '.join(stack_templates.keys())}")
    
    # Create output directory if it doesn't exist
    os.makedirs(output_dir, exist_ok=True)
    
    # Clean up old template files to avoid stale stacks
    old_files_removed = False
    if os.path.exists(output_dir):
        for filename in os.listdir(output_dir):
            if filename.endswith('.json'):
                old_file = os.path.join(output_dir, filename)
                os.remove(old_file)
                click.echo(f"Removed old template: {old_file}")
                old_files_removed = True
    
    if not old_files_removed and stack_templates:
        click.echo("No old templates to clean up.")
    
    # Save each stack template to a separate file
    saved_files = []
    for stack_name, cf_template_json in stack_templates.items():
        output_file = os.path.join(output_dir, f"{stack_name}.json")
        with open(output_file, 'w') as f:
            f.write(cf_template_json)
        saved_files.append(output_file)
        click.echo(f"Generated template for stack '{stack_name}': {output_file}")
    
    if saved_files:
        click.echo(f"\nSuccessfully generated {len(saved_files)} CloudFormation template(s) in '{output_dir}'")
    else:
        click.echo("No templates were generated.")

@cli.command()
@click.argument('path', type=click.Path(exists=True, file_okay=True, dir_okay=True), required=False, default='.')
@click.option('--stacks', '-s', multiple=True, 
              help='Specific stack names to validate. If not provided, validates all stacks.')
@click.option('--deploy-role-arn', help='ARN of the IAM role to assume for validation.')
@click.option('--output-dir', '-o', default='iicy.out', 
              help='Output directory for CloudFormation templates (defaults to iicy.out).')
def validate(path, stacks, deploy_role_arn, output_dir):
    """
    Analyzes code, generates CloudFormation templates, and validates them using AWS CloudFormation service.
    
    If no path is provided, analyzes the current working directory.
    """
    # 1. Analyze code and determine stack names
    click.echo("1. Analyzing code to determine stack configurations...")
    pipeline = InfraPipeline()
    stack_templates = pipeline.generate(path)
    
    if not stack_templates:
        click.echo("No stacks found to validate.", err=True)
        return
    
    stack_names = list(stack_templates.keys())
    click.echo(f"   Found stacks: {', '.join(stack_names)}")
    
    # Filter stacks if specific stacks are requested
    if stacks:
        # Convert to set for efficient lookup
        requested_stacks = set(stacks)
        available_stacks = set(stack_names)
        
        # Check if all requested stacks exist
        missing_stacks = requested_stacks - available_stacks
        if missing_stacks:
            click.echo(f"Error: Requested stacks not found: {', '.join(missing_stacks)}", err=True)
            click.echo(f"Available stacks: {', '.join(available_stacks)}", err=True)
            return
        
        # Filter stack templates to only include requested stacks
        stack_templates = {name: template for name, template in stack_templates.items() if name in requested_stacks}
        stack_names = list(stack_templates.keys())
        click.echo(f"   Validating stacks: {', '.join(stack_names)}")

    # 2. Save templates to output directory
    os.makedirs(output_dir, exist_ok=True)
    
    # Clean up old template files to avoid stale stacks
    old_files_removed = False
    if os.path.exists(output_dir):
        for filename in os.listdir(output_dir):
            if filename.endswith('.json'):
                old_file = os.path.join(output_dir, filename)
                os.remove(old_file)
                click.echo(f"   Removed old template: {old_file}")
                old_files_removed = True
    
    if not old_files_removed and stack_templates:
        click.echo("   No old templates to clean up.")
    
    template_files = {}
    
    for stack_name, cf_template_json in stack_templates.items():
        template_file = os.path.join(output_dir, f"{stack_name}.json")
        with open(template_file, 'w') as f:
            f.write(cf_template_json)
        template_files[stack_name] = template_file
        click.echo(f"   Generated template for stack '{stack_name}': {template_file}")

    # 3. Validate each CloudFormation template
    click.echo("3. Validating CloudFormation templates...")
    cloudformation = get_aws_client('cloudformation', deploy_role_arn)
    validation_results = {}
    
    for stack_name, cf_template_json in stack_templates.items():
        click.echo(f"   Validating stack '{stack_name}'...")
        is_valid, message = validate_template(cf_template_json, cloudformation)
        validation_results[stack_name] = (is_valid, message)
        
        if is_valid:
            click.echo(f"      ✅ {message}")
        else:
            click.echo(f"      ❌ {message}", err=True)

    # 4. Summary
    click.echo("\n4. Validation Summary:")
    valid_count = sum(1 for is_valid, _ in validation_results.values() if is_valid)
    total_count = len(validation_results)
    
    if valid_count == total_count:
        click.echo(f"   ✅ All {total_count} template(s) are valid!")
    else:
        click.echo(f"   ❌ {total_count - valid_count} of {total_count} template(s) failed validation.", err=True)
        click.echo("   Please fix the validation errors before deploying.", err=True)

@cli.command()
@click.option('--path', type=click.Path(exists=True, file_okay=True, dir_okay=True), default='.',
              help='Path to analyze for determining stack names (defaults to current directory).')
@click.option('--deploy-role-arn', help='ARN of the IAM role to assume for deployment.')
def sync_infra(path, deploy_role_arn):
    """
    Fetches CloudFormation stack outputs and populates infra.yml based on stacks found in code.
    """
    cloudformation = get_aws_client('cloudformation', deploy_role_arn)
    
    # Determine stack names from code analysis
    click.echo("Analyzing code to determine stack names...")
    pipeline = InfraPipeline()
    stack_names = pipeline.get_stack_names(path)
    
    if not stack_names:
        click.echo("No stacks found in the analyzed code.", err=True)
        return
        
    click.echo(f"Found stacks: {', '.join(stack_names)}")
    
    from .features.infra.infra_config import InfraConfig
    
    # Load existing config or create new one
    try:
        infra_config = InfraConfig.load()
    except FileNotFoundError:
        infra_config = InfraConfig()

    for stack_name in stack_names:
        click.echo(f"Syncing outputs from stack '{stack_name}'...")
        try:
            response = cloudformation.describe_stacks(StackName=stack_name)
            outputs = response['Stacks'][0]['Outputs']

            # Store all outputs in the exports
            for output in outputs:
                output_key = output['OutputKey']
                output_value = output['OutputValue']
                infra_config.exports[output_key] = output_value

            click.echo(f"   Successfully synced outputs from stack '{stack_name}'.")

        except cloudformation.exceptions.ClientError as e:
            if "Stack with id " + stack_name + " does not exist" in str(e):
                click.echo(f"   Warning: CloudFormation stack '{stack_name}' not found, skipping.", err=True)
            else:
                click.echo(f"   Error fetching stack outputs for '{stack_name}': {e}", err=True)
        except Exception as e:
            click.echo(f"   An unexpected error occurred for stack '{stack_name}': {e}", err=True)

    # Save the updated config
    infra_config.save()

    click.echo(f"Successfully populated infra.yml from {len(stack_names)} stack(s).")

@cli.command()
@click.argument('path', type=click.Path(exists=True, file_okay=True, dir_okay=True), required=False, default='.')
@click.option('--stacks', '-s', multiple=True, 
              help='Specific stack names to deploy. If not provided, deploys all stacks.')
@click.option('--capabilities', '-c', multiple=True, default=['CAPABILITY_NAMED_IAM'],
              help='Capabilities to pass to CloudFormation (e.g., CAPABILITY_IAM, CAPABILITY_NAMED_IAM).')
@click.option('--deploy-role-arn', help='ARN of the IAM role to assume for deployment.')
@click.option('--output-dir', '-o', default='iicy.out', 
              help='Output directory for CloudFormation templates (defaults to iicy.out).')
@click.option('--no-validate', is_flag=True, default=False,
              help='Skip CloudFormation template validation before deployment.')
@click.option('--verbose', '-v', is_flag=True, default=False,
              help='Show detailed deployment progress with real-time CloudFormation events.')
def deploy(path, stacks, capabilities, deploy_role_arn, output_dir, no_validate, verbose):
    """
    Analyzes code, deploys CloudFormation stacks, and syncs infra.yml.
    
    If no path is provided, analyzes the current working directory.
    """
    # 1. Analyze code and determine stack names
    click.echo("1. Analyzing code to determine stack configurations...")
    pipeline = InfraPipeline()
    stack_templates = pipeline.generate(path)
    
    if not stack_templates:
        click.echo("No stacks found to deploy.", err=True)
        return
    
    stack_names = list(stack_templates.keys())
    click.echo(f"   Found stacks: {', '.join(stack_names)}")
    
    # Filter stacks if specific stacks are requested
    if stacks:
        # Convert to set for efficient lookup
        requested_stacks = set(stacks)
        available_stacks = set(stack_names)
        
        # Check if all requested stacks exist
        missing_stacks = requested_stacks - available_stacks
        if missing_stacks:
            click.echo(f"Error: Requested stacks not found: {', '.join(missing_stacks)}", err=True)
            click.echo(f"Available stacks: {', '.join(available_stacks)}", err=True)
            return
        
        # Filter stack templates to only include requested stacks
        stack_templates = {name: template for name, template in stack_templates.items() if name in requested_stacks}
        stack_names = list(stack_templates.keys())
        click.echo(f"   Deploying stacks: {', '.join(stack_names)}")

    # 2. Save templates to output directory
    os.makedirs(output_dir, exist_ok=True)
    
    # Clean up old template files to avoid stale stacks
    old_files_removed = False
    if os.path.exists(output_dir):
        for filename in os.listdir(output_dir):
            if filename.endswith('.json'):
                old_file = os.path.join(output_dir, filename)
                os.remove(old_file)
                click.echo(f"   Removed old template: {old_file}")
                old_files_removed = True
    
    if not old_files_removed and stack_templates:
        click.echo("   No old templates to clean up.")
    
    template_files = {}
    
    for stack_name, cf_template_json in stack_templates.items():
        template_file = os.path.join(output_dir, f"{stack_name}.json")
        with open(template_file, 'w') as f:
            f.write(cf_template_json)
        template_files[stack_name] = template_file
        click.echo(f"   Generated template for stack '{stack_name}': {template_file}")

    # 3. Validate templates (unless --no-validate is specified)
    cloudformation = get_aws_client('cloudformation', deploy_role_arn)
    
    if not no_validate:
        click.echo("3. Validating CloudFormation templates...")
        validation_failed = False
        
        for stack_name, cf_template_json in stack_templates.items():
            click.echo(f"   Validating stack '{stack_name}'...")
            is_valid, message = validate_template(cf_template_json, cloudformation)
            
            if is_valid:
                click.echo(f"      ✅ {message}")
            else:
                click.echo(f"      ❌ {message}", err=True)
                validation_failed = True
        
        if validation_failed:
            click.echo("\n   ❌ Template validation failed. Deployment aborted.", err=True)
            click.echo("   Use --no-validate to skip validation, or fix the validation errors.", err=True)
            return
        else:
            click.echo("   ✅ All templates are valid!")
    else:
        click.echo("3. Skipping template validation (--no-validate specified)...")

    # 4. Pre-deployment: Package and upload Lambda code
    click.echo("4. Pre-deployment: Packaging and uploading Lambda code...")
    try:
        # Get AWS session for S3 operations
        if deploy_role_arn:
            # If using a role, create a new session with the role credentials
            sts_client = boto3.client('sts')
            try:
                assumed_role_object = sts_client.assume_role(
                    RoleArn=deploy_role_arn,
                    RoleSessionName="IICYDeploymentSession"
                )
                credentials = assumed_role_object['Credentials']
                session = boto3.Session(
                    aws_access_key_id=credentials['AccessKeyId'],
                    aws_secret_access_key=credentials['SecretAccessKey'],
                    aws_session_token=credentials['SessionToken'],
                )
            except Exception as e:
                raise click.ClickException(f"Failed to assume role {deploy_role_arn}: {e}")
        else:
            # Use default session
            session = boto3.Session()
        
        # Re-run discovery to get Lambda configurations
        from .features.lambda_.lambda_feature import LambdaFeature
        from .models.context import DiscoveryStageContext, GenerationStageContext
        from pathlib import Path
        import glob
        
        # Discover Lambda configurations
        lambda_feature = LambdaFeature()
        discovered_configs = []
        
        # Process all Python files to discover Lambda configs
        # Handle both file and directory paths
        if os.path.isfile(path) and path.endswith('.py'):
            python_files = [path]
        else:
            python_files = glob.glob(os.path.join(path, '**', '*.py'), recursive=True)
        
        for file_path in python_files:
            discovery_context = DiscoveryStageContext(file_path=Path(file_path))
            configs = lambda_feature.discover(discovery_context)
            discovered_configs.extend(configs)
        
        if discovered_configs:
            # Group configs by stack
            stacks = {}
            for config in discovered_configs:
                stack_name = getattr(config, 'stack', 'IICYStack')
                if stack_name not in stacks:
                    stacks[stack_name] = []
                stacks[stack_name].append(config)
            
            # Process each stack
            for stack_name, configs in stacks.items():
                # Package and upload Lambda code for each config
                for config in configs:
                    try:
                        print(f"📦 Packaging Lambda function: {config.function_name}")
                        # Use the same bucket naming pattern as CloudFormation template
                        bucket_name = f"{config.logical_id.lower()}-deployment-bucket"
                        lambda_feature._ensure_s3_bucket_for_upload(bucket_name, session)
                        s3_key = lambda_feature.package_and_upload_lambda(config, bucket_name, session)
                        print(f"✅ Lambda function {config.function_name} packaged and uploaded to S3")
                    except Exception as e:
                        print(f"❌ Failed to package Lambda function {config.function_name}: {e}")
                        raise
                
            click.echo("✅ Lambda code packaging and upload completed")
        else:
            click.echo("   No Lambda functions found to package")
            
    except Exception as e:
        click.echo(f"   ❌ Pre-deployment failed: {e}", err=True)
        return

    # 5. Deploy each CloudFormation stack
    click.echo("5. Deploying CloudFormation stacks...")
    deployed_stacks = []
    
    for stack_name, cf_template_json in stack_templates.items():
        click.echo(f"   Processing stack '{stack_name}'...")
        template_file = template_files[stack_name]

        try:
            # Check if stack exists to decide between create or update
            stack_exists = False
            try:
                cloudformation.describe_stacks(StackName=stack_name)
                stack_exists = True
            except cloudformation.exceptions.ClientError as e:
                if "Stack with id " + stack_name + " does not exist" not in str(e):
                    raise # Re-raise if it's not a "stack not found" error

            if stack_exists:
                click.echo(f"      Stack '{stack_name}' exists. Attempting update...")
                response = cloudformation.update_stack(
                    StackName=stack_name,
                    TemplateBody=cf_template_json,
                    Capabilities=list(capabilities)
                )
                click.echo(f"      Update initiated: {response['StackId']}")
            else:
                click.echo(f"      Stack '{stack_name}' does not exist. Attempting creation...")
                response = cloudformation.create_stack(
                    StackName=stack_name,
                    TemplateBody=cf_template_json,
                    Capabilities=list(capabilities)
                )
                click.echo(f"      Creation initiated: {response['StackId']}")

            # Wait for stack operation to complete
            if verbose:
                click.echo(f"      Deploying stack '{stack_name}' with detailed status monitoring...")
                from .utils.deployment_monitor import monitor_deployment
                success = monitor_deployment(cloudformation, stack_name, timeout_minutes=10)
            else:
                click.echo(f"      Waiting for stack '{stack_name}' operation to complete...")
                waiter = cloudformation.get_waiter('stack_create_complete') if not stack_exists else cloudformation.get_waiter('stack_update_complete')
                waiter.wait(StackName=stack_name,
                            WaiterConfig={'Delay': 10, 'MaxAttempts': 60}) # 10 min timeout
                success = True
            
            if success:
                click.echo(f"      Stack '{stack_name}' operation completed successfully.")
            else:
                click.echo(f"      Stack '{stack_name}' operation failed.", err=True)
                continue  # Skip to next stack
            deployed_stacks.append(stack_name)

        except cloudformation.exceptions.ClientError as e:
            click.echo(f"      Error deploying CloudFormation stack '{stack_name}': {e}", err=True)
            continue # Continue with other stacks
        except Exception as e:
            click.echo(f"      An unexpected error occurred during stack '{stack_name}' deployment: {e}", err=True)
            continue # Continue with other stacks

    if not deployed_stacks:
        click.echo("No stacks were successfully deployed.", err=True)
        return


    # 6. Sync infra.yml
    click.echo("6. Syncing infra.yml...")
    try:
        from .features.infra.infra_config import InfraConfig
        
        # Load existing config or create new one
        try:
            infra_config = InfraConfig.load()
        except FileNotFoundError:
            infra_config = InfraConfig()
            
        for stack_name in deployed_stacks:
            click.echo(f"   Syncing outputs from stack '{stack_name}'...")
            response = cloudformation.describe_stacks(StackName=stack_name)
            outputs = response['Stacks'][0]['Outputs']

            # Store all outputs in the exports
            for output in outputs:
                output_key = output['OutputKey']
                output_value = output['OutputValue']
                infra_config.exports[output_key] = output_value

        # Save the updated config
        infra_config.save()
        click.echo(f"   Successfully populated infra.yml from {len(deployed_stacks)} stack(s).")
    except Exception as e:
        click.echo(f"Error syncing infra.yml: {e}", err=True)
        return

    click.echo(f"Full deployment process for {len(deployed_stacks)} stack(s) completed successfully!")

@cli.command()
@click.option('--path', type=click.Path(exists=True, file_okay=True, dir_okay=True), default='.',
              help='Path to analyze for determining stack names (defaults to current directory).')
@click.option('--stacks', '-s', multiple=True, 
              help='Specific stack names to destroy. If not provided, destroys all stacks.')
@click.option('--delete-infra-file', is_flag=True, default=True,
              help='Also delete the infra.yml file after destroying the stack.')
@click.option('--deploy-role-arn', help='ARN of the IAM role to assume for deployment.')
@click.option('--verbose', '-v', is_flag=True, default=False,
              help='Show detailed destruction progress with real-time CloudFormation events.')
def destroy(path, stacks, delete_infra_file, deploy_role_arn, verbose):
    """
    Destroys CloudFormation stacks based on code analysis and optionally removes infra.yml.
    """
    # Determine stack names from code analysis
    click.echo("Analyzing code to determine stack names...")
    pipeline = InfraPipeline()
    stack_names = pipeline.get_stack_names(path)
    
    if not stack_names:
        click.echo("No stacks found in the analyzed code.", err=True)
        return
    
    # Filter stacks if specific stacks are requested
    if stacks:
        # Convert to set for efficient lookup
        requested_stacks = set(stacks)
        available_stacks = set(stack_names)
        
        # Check if all requested stacks exist
        missing_stacks = requested_stacks - available_stacks
        if missing_stacks:
            click.echo(f"Error: Requested stacks not found: {', '.join(missing_stacks)}", err=True)
            click.echo(f"Available stacks: {', '.join(available_stacks)}", err=True)
            return
        
        # Filter stack names to only include requested stacks
        stack_names = [name for name in stack_names if name in requested_stacks]
        click.echo(f"Destroying stacks: {', '.join(stack_names)}")
    else:
        click.echo(f"Found stacks to destroy: {', '.join(stack_names)}")
        
    cloudformation = get_aws_client('cloudformation', deploy_role_arn)
    destroyed_stacks = []

    for stack_name in stack_names:
        click.echo(f"Processing stack '{stack_name}'...")
        try:
            click.echo(f"   Deleting CloudFormation stack '{stack_name}'...")
            cloudformation.delete_stack(StackName=stack_name)
            if verbose:
                click.echo(f"   Deletion initiated. Monitoring stack '{stack_name}' destruction...")
                from .utils.deployment_monitor import monitor_deployment
                success = monitor_deployment(cloudformation, stack_name, timeout_minutes=10)
                
                if success:
                    click.echo(f"   Stack '{stack_name}' destroyed successfully.")
                else:
                    click.echo(f"   Stack '{stack_name}' destruction failed.", err=True)
                    continue  # Skip to next stack
            else:
                click.echo(f"   Deletion initiated. Waiting for stack '{stack_name}' to be destroyed...")
                waiter = cloudformation.get_waiter('stack_delete_complete')
                waiter.wait(StackName=stack_name,
                            WaiterConfig={'Delay': 10, 'MaxAttempts': 60}) # 10 min timeout
                click.echo(f"   Stack '{stack_name}' destroyed successfully.")
            destroyed_stacks.append(stack_name)

        except cloudformation.exceptions.ClientError as e:
            if "Stack with id " + stack_name + " does not exist" in str(e):
                click.echo(f"   Stack '{stack_name}' does not exist or already deleted. Skipping deletion.")
                destroyed_stacks.append(stack_name)  # Consider it as destroyed
            else:
                click.echo(f"   Error destroying CloudFormation stack '{stack_name}': {e}", err=True)
        except Exception as e:
            click.echo(f"   An unexpected error occurred during stack '{stack_name}' destruction: {e}", err=True)

    # Clean up Lambda deployment S3 buckets
    if destroyed_stacks:
        try:
            # Create session with the same role assumption logic as CloudFormation client
            if deploy_role_arn:
                sts_client = boto3.client('sts')
                try:
                    assumed_role_object = sts_client.assume_role(
                        RoleArn=deploy_role_arn,
                        RoleSessionName="IICYDeploymentSession"
                    )
                    credentials = assumed_role_object['Credentials']
                    session = boto3.Session(
                        aws_access_key_id=credentials['AccessKeyId'],
                        aws_secret_access_key=credentials['SecretAccessKey'],
                        aws_session_token=credentials['SessionToken'],
                    )
                except Exception as e:
                    click.echo(f"Failed to assume role {deploy_role_arn} for S3 cleanup: {e}", err=True)
                    session = boto3.Session()  # Fall back to default session
            else:
                session = boto3.Session()
            
            # Import and call the S3 cleanup utility
            from .utils.s3_cleanup import cleanup_deployment_buckets
            cleanup_deployment_buckets(destroyed_stacks, session)
            
        except Exception as e:
            click.echo(f"Error during S3 bucket cleanup: {e} (continuing)", err=True)

    if delete_infra_file and destroyed_stacks:
        click.echo("Removing infra.yml...")
        infra_file_path = os.path.join(os.getcwd(), 'infra.yml')
        if os.path.exists(infra_file_path):
            os.remove(infra_file_path)
            click.echo("   infra.yml removed.")
        else:
            click.echo("   infra.yml not found. Skipping removal.")

    if destroyed_stacks:
        click.echo(f"Full destruction process completed for {len(destroyed_stacks)} stack(s)!")
    else:
        click.echo("No stacks were successfully destroyed.")


if __name__ == '__main__':
    cli()
