#!/usr/bin/env python3
"""
Cleanup and teardown engine for C2ingRed deployments
"""

import os
import sys
import subprocess
import logging
import json
import glob

# Add project root to path
sys.path.append(os.path.join(os.path.dirname(__file__), '..', '..'))

from utils.common import COLORS, PROVIDER_DIRS, confirm_action

def teardown_by_deployment_id(deployment_id):
    """Teardown infrastructure by deployment ID"""
    print(f"\n{COLORS['BLUE']}Teardown Infrastructure by ID: {deployment_id}{COLORS['RESET']}")
    
    # Look for deployment logs to determine provider and configuration
    log_files = glob.glob(f"logs/deployment_{deployment_id}*.log")
    
    if not log_files:
        print(f"{COLORS['RED']}No deployment logs found for ID: {deployment_id}{COLORS['RESET']}")
        return False
    
    # Try to find deployment info files
    info_files = glob.glob(f"logs/deployment_info_{deployment_id}*.txt")
    
    if info_files:
        config = parse_deployment_info(info_files[0])
        if config:
            return execute_teardown(config)
    
    print(f"{COLORS['YELLOW']}Could not determine deployment configuration from logs{COLORS['RESET']}")
    print(f"{COLORS['YELLOW']}Manual cleanup may be required{COLORS['RESET']}")
    return False

def teardown_all_infrastructure():
    """Teardown all deployed infrastructure"""
    print(f"\n{COLORS['RED']}⚠️  WARNING: This will attempt to destroy ALL infrastructure!{COLORS['RESET']}")
    
    if not confirm_action("Are you absolutely sure?", default=False):
        return False
    
    # Find all deployment info files
    info_files = glob.glob("logs/deployment_info_*.txt")
    
    if not info_files:
        print(f"{COLORS['GREEN']}No deployment info files found - nothing to teardown{COLORS['RESET']}")
        return True
    
    print(f"Found {len(info_files)} deployments to teardown:")
    
    success_count = 0
    for info_file in info_files:
        config = parse_deployment_info(info_file)
        if config:
            deployment_id = config.get('deployment_id', 'unknown')
            print(f"\nTearing down deployment: {deployment_id}")
            if execute_teardown(config):
                success_count += 1
    
    print(f"\n{COLORS['GREEN']}Successfully tore down {success_count}/{len(info_files)} deployments{COLORS['RESET']}")
    return success_count == len(info_files)

def parse_deployment_info(info_file):
    """Parse deployment info from file to extract configuration"""
    try:
        config = {}
        with open(info_file, 'r') as f:
            lines = f.readlines()
        
        in_config_section = False
        for line in lines:
            line = line.strip()
            
            if line == "Configuration:":
                in_config_section = True
                continue
            elif line.startswith("-" * 30):
                continue
            elif line.startswith("Access Information:"):
                break
                
            if in_config_section and ": " in line:
                key, value = line.split(": ", 1)
                
                # Convert string values back to appropriate types
                if value.lower() == 'true':
                    value = True
                elif value.lower() == 'false':
                    value = False
                elif value.lower() == 'none':
                    value = None
                
                config[key] = value
        
        return config
    except Exception as e:
        logging.error(f"Failed to parse deployment info from {info_file}: {e}")
        return None

def execute_teardown(config):
    """Execute teardown based on configuration"""
    provider = config.get('provider')
    deployment_id = config.get('deployment_id')
    
    if not provider or not deployment_id:
        print(f"{COLORS['RED']}Missing provider or deployment ID{COLORS['RESET']}")
        return False
    
    print(f"{COLORS['BLUE']}Executing teardown for {provider} deployment {deployment_id}...{COLORS['RESET']}")
    
    # Set up logging for teardown
    from utils.common import setup_logging
    setup_logging(deployment_id, "teardown")
    
    try:
        # Set provider-specific environment variables
        set_provider_environment_for_teardown(config)
        
        # Get correct provider directory
        provider_dir = PROVIDER_DIRS.get(provider, provider.capitalize())
        
        # Execute teardown playbook
        playbook = f"providers/{provider_dir}/cleanup.yml"
        
        if not os.path.exists(playbook):
            print(f"{COLORS['YELLOW']}Teardown playbook not found: {playbook}{COLORS['RESET']}")
            print(f"{COLORS['YELLOW']}Manual cleanup required{COLORS['RESET']}")
            return manual_cleanup_guidance(config)
        
        success = run_teardown_playbook(playbook, config)
        
        if success:
            # Clean up local SSH keys
            cleanup_ssh_keys_for_deployment(deployment_id)
            
            # Move deployment logs to cleanup folder
            archive_deployment_logs(deployment_id)
            
            print(f"{COLORS['GREEN']}Teardown completed successfully{COLORS['RESET']}")
        else:
            print(f"{COLORS['RED']}Teardown failed - manual cleanup may be required{COLORS['RESET']}")
        
        return success
        
    except Exception as e:
        logging.error(f"Teardown execution failed: {e}")
        print(f"{COLORS['RED']}Teardown execution failed: {e}{COLORS['RESET']}")
        return False

def set_provider_environment_for_teardown(config):
    """Set provider-specific environment variables for teardown"""
    provider = config.get('provider')
    
    if provider == "aws":
        if config.get('aws_access_key'):
            os.environ['AWS_ACCESS_KEY_ID'] = config['aws_access_key']
        if config.get('aws_secret_key'):
            os.environ['AWS_SECRET_ACCESS_KEY'] = config['aws_secret_key']
    elif provider == "linode":
        # Try to get token from config first, then from vars file
        if config.get('linode_token'):
            os.environ['LINODE_TOKEN'] = config['linode_token']
        else:
            # Load token from provider vars file
            try:
                from utils.common import load_vars_file, PROVIDER_DIRS
                vars_data = load_vars_file(provider)
                if vars_data and vars_data.get('linode_token'):
                    os.environ['LINODE_TOKEN'] = vars_data['linode_token']
                    config['linode_token'] = vars_data['linode_token']  # Add to config for later use
                else:
                    logging.warning("Linode token not found in vars file - cleanup may fail")
            except Exception as e:
                logging.warning(f"Failed to load Linode token from vars file: {e}")

def run_teardown_playbook(playbook, config):
    """Run the teardown Ansible playbook"""
    try:
        cmd = [
            'ansible-playbook',
            playbook,
            '--extra-vars', create_teardown_vars(config)
        ]
        
        if config.get('debug'):
            cmd.append('-vvv')
        
        logging.info(f"Executing teardown: {' '.join(cmd)}")
        
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
            cwd=os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
        )
        
        if result.returncode == 0:
            logging.info("Teardown playbook executed successfully")
            return True
        else:
            logging.error(f"Teardown playbook failed with return code {result.returncode}")
            logging.error(f"STDOUT: {result.stdout}")
            logging.error(f"STDERR: {result.stderr}")
            return False
            
    except Exception as e:
        logging.error(f"Error executing teardown playbook: {e}")
        return False

def create_teardown_vars(config):
    """Create Ansible extra vars for teardown"""
    teardown_vars = {
        'deployment_id': config.get('deployment_id'),
        'provider': config.get('provider'),
        'operation': 'teardown'
    }
    
    # Add instance names for proper cleanup
    if config.get('redirector_name'):
        teardown_vars['redirector_name'] = config['redirector_name']
    if config.get('c2_name'):
        teardown_vars['c2_name'] = config['c2_name']
    if config.get('tracker_name'):
        teardown_vars['tracker_name'] = config['tracker_name']
    if config.get('attack_box_name'):
        teardown_vars['attack_box_name'] = config['attack_box_name']
    
    # Add provider-specific vars if present
    if config.get('aws_access_key'):
        teardown_vars['aws_access_key'] = config['aws_access_key']
    if config.get('aws_secret_key'):
        teardown_vars['aws_secret_key'] = config['aws_secret_key']
    if config.get('aws_region'):
        teardown_vars['aws_region'] = config['aws_region']
    if config.get('linode_token'):
        teardown_vars['linode_token'] = config['linode_token']
    if config.get('linode_region'):
        teardown_vars['linode_region'] = config['linode_region']
    
    return json.dumps(teardown_vars)

def cleanup_ssh_keys_for_deployment(deployment_id):
    """Clean up SSH keys for a specific deployment"""
    ssh_dir = os.path.expanduser("~/.ssh")
    key_pattern = f"c2deploy_{deployment_id}*"
    
    for key_file in glob.glob(os.path.join(ssh_dir, key_pattern)):
        try:
            os.remove(key_file)
            logging.info(f"Removed SSH key: {key_file}")
        except Exception as e:
            logging.warning(f"Failed to remove SSH key {key_file}: {e}")

def archive_deployment_logs(deployment_id):
    """Archive deployment logs after successful teardown"""
    try:
        # Create archive directory
        archive_dir = "logs/archive"
        os.makedirs(archive_dir, exist_ok=True)
        
        # Move all files related to this deployment
        log_patterns = [
            f"logs/deployment_{deployment_id}*",
            f"logs/deployment_info_{deployment_id}*",
            f"logs/teardown_{deployment_id}*"
        ]
        
        for pattern in log_patterns:
            for file_path in glob.glob(pattern):
                archive_path = os.path.join(archive_dir, os.path.basename(file_path))
                os.rename(file_path, archive_path)
                logging.info(f"Archived: {file_path} -> {archive_path}")
                
    except Exception as e:
        logging.warning(f"Failed to archive logs for {deployment_id}: {e}")

def manual_cleanup_guidance(config):
    """Provide manual cleanup guidance when automated teardown isn't available"""
    provider = config.get('provider')
    deployment_id = config.get('deployment_id')
    
    print(f"\n{COLORS['YELLOW']}Manual Cleanup Required{COLORS['RESET']}")
    print(f"{COLORS['YELLOW']}========================{COLORS['RESET']}")
    print(f"Deployment ID: {deployment_id}")
    print(f"Provider: {provider}")
    
    if provider == "aws":
        print(f"\nAWS Resources to check:")
        print(f"- EC2 instances with tags containing: {deployment_id}")
        print(f"- Security groups with names containing: {deployment_id}")
        print(f"- Key pairs with names containing: {deployment_id}")
        print(f"- EIPs associated with the deployment")
        
    elif provider == "linode":
        print(f"\nLinode Resources to check:")
        print(f"- Linodes with labels containing: {deployment_id}")
        print(f"- NodeBalancers with labels containing: {deployment_id}")
        print(f"- Firewalls with labels containing: {deployment_id}")
        
    elif provider == "flokinet":
        print(f"\nFlokiNET Resources to check:")
        print(f"- Check your FlokiNET control panel for resources created")
        print(f"- Look for servers with the deployment ID: {deployment_id}")
    
    print(f"\nLocal cleanup:")
    print(f"- SSH keys: ~/.ssh/c2deploy_{deployment_id}*")
    print(f"- Log files: logs/*{deployment_id}*")
    
    return False  # Manual cleanup required

if __name__ == "__main__":
    print("Cleanup engine loaded")
