"""
CloudZero connection recreation for optimized first ingest.

Handles the complete workflow of deleting existing connections, cleaning S3 folders,
and recreating connections to leverage CloudZero's first ingest performance optimization.
"""

from typing import Dict, List, Any, Optional
from dataclasses import dataclass
from datetime import datetime

from ..s3.config import Organization
from ..s3.folder_manager import S3FolderManager, FolderDeletionResult
from ..api.client import CloudZeroAPI
from src.log_context import get_logger


@dataclass
class ConnectionRecreationResult:
    """Result of connection recreation for an organization."""
    org: str
    deleted_connections: List[str]
    created_connections: List[str]
    deleted_folders: List[FolderDeletionResult]
    status: str  # "success", "partial", "failed"
    error_message: Optional[str] = None
    duration_seconds: float = 0


class ConnectionRecreator:
    """
    Handles connection deletion and recreation workflow.
    
    Coordinates the complete process of:
    1. Deleting existing CloudZero connections
    2. Cleaning S3 org provider folders
    3. Recreating connections for optimized first ingest
    """
    
    def __init__(self, bucket: str, region: str = "us-east-1"):
        """
        Initialize connection recreator.
        
        Args:
            bucket: S3 bucket name
            region: AWS region
        """
        self.bucket = bucket
        self.region = region
        self.logger = get_logger(__name__)
        
        # Initialize services
        self.folder_manager = S3FolderManager(bucket, region)
    
    def recreate_org_connections(self, org: Organization, dry_run: bool = False) -> ConnectionRecreationResult:
        """
        Recreate all connections for an organization.
        
        Args:
            org: Organization configuration
            dry_run: If True, don't actually delete/create, just return what would happen
            
        Returns:
            ConnectionRecreationResult with recreation summary
        """
        start_time = datetime.now()
        result = ConnectionRecreationResult(
            org=org.name,
            deleted_connections=[],
            created_connections=[],
            deleted_folders=[],
            status="success"
        )
        
        self.logger.info(f"{'DRY RUN: ' if dry_run else ''}Starting connection recreation for {org.name}")
        
        # Initialize CloudZero client with org's API token
        cz_client = CloudZeroAPI(org.api_token_env)
        
        # Phase 1: Delete existing CloudZero connections
        self.logger.info(f"Phase 1: Deleting existing connections for {org.name}")
        
        # Auto-discover existing connections for each provider instead of relying on config
        for provider in org.providers:
            try:
                    # Find existing connection for this provider using the same logic as upload
                    existing_connection = cz_client.find_enabled_bucket_connection(provider)
                    
                    if existing_connection:
                        conn_id = existing_connection['id']
                        conn_name = existing_connection['name']
                        
                        if not dry_run:
                            # Actual connection deletion using CloudZero API
                            self.logger.info(f"Deleting connection: {conn_name} ({conn_id})")
                            success = cz_client.delete_billing_connection(conn_id)
                            if success:
                                result.deleted_connections.append(conn_name)
                                self.logger.info(f"Deleted connection: {conn_name}")
                            else:
                                self.logger.error(f"Failed to delete connection: {conn_name}")
                                result.status = "partial"
                                if not result.error_message:
                                    result.error_message = f"Failed to delete connection: {conn_name}"
                        else:
                            # Dry run - just log what would be deleted
                            result.deleted_connections.append(conn_name)
                            self.logger.info(f"Would delete connection: {conn_name} ({conn_id})")
                    else:
                        self.logger.info(f"No existing connection found for {provider}")
                        
                except Exception as e:
                    self.logger.error(f"Failed to process connection for {provider}: {e}")
                    result.status = "partial"
                    if not result.error_message:
                        result.error_message = f"Failed to process connections: {e}"
            
            # Phase 2: Delete S3 org provider folders
            self.logger.info(f"Phase 2: Deleting S3 folders for {org.name}")
            for provider in org.providers:
                folder_result = self.folder_manager.delete_org_provider_folder(
                    org.name, provider, dry_run=dry_run
                )
                result.deleted_folders.append(folder_result)
                
                if not folder_result.success:
                    self.logger.error(f"Failed to delete folder for {org.name}/{provider}: {folder_result.error_message}")
                    result.status = "partial"
                    if not result.error_message:
                        result.error_message = f"Failed to delete some S3 folders: {folder_result.error_message}"
                else:
                    self.logger.info(f"{'Would delete' if dry_run else 'Deleted'} {folder_result.objects_deleted} objects from {folder_result.prefix}")
            
            # Phase 3: Recreate connections (triggers first ingest behavior)
            self.logger.info(f"Phase 3: Recreating connections for {org.name}")
            
            # Recreate connections for providers that had connections deleted
            if result.deleted_connections:
                for provider in org.providers:
                    # Only recreate if we had a connection for this provider
                    from ..api.connection_manager import generate_provider_connection_name
                    expected_conn_name = generate_provider_connection_name(provider)
                    
                    if expected_conn_name in result.deleted_connections:
                        try:
                            if not dry_run:
                                # Recreate the connection using the same parameters as upload
                                from ..api.connection_manager import create_cloudzero_connection
                                from src.services.environment_service import EnvironmentService
                                
                                env_service = EnvironmentService()
                                s3_bucket_name = env_service.require("CZBILLGEN_S3_BUCKET")
                                s3_root_folder = "piedpiper-custom-billing"  # For generated uploads
                                s3_org_folder = org.name
                                role_arn = env_service.require("AWS_IAM_ROLE_ARN")
                                external_id = env_service.require("AWS_IAM_EXTERNAL_ID")
                                
                                new_connection = create_cloudzero_connection(
                                    provider=provider,
                                    s3_bucket_name=s3_bucket_name,
                                    s3_root_folder=s3_root_folder,
                                    s3_org_folder=s3_org_folder,
                                    role_arn=role_arn,
                                    external_id=external_id
                                )
                                
                                new_conn_name = new_connection['name']
                                result.created_connections.append(new_conn_name)
                                self.logger.info(f"Created connection: {new_conn_name}")
                            else:
                                # Dry run - just log what would be created
                                result.created_connections.append(expected_conn_name)
                                self.logger.info(f"Would create connection: {expected_conn_name}")
                                
                        except Exception as e:
                            error_str = str(e)
                            # Check for permission errors that should cause immediate failure
                            if "403" in error_str or "not authorized" in error_str.lower():
                                result.status = "failed"
                                result.error_message = f"FATAL: Insufficient CloudZero API permissions: {e}"
                                self.logger.error(f"FATAL: CloudZero API permission denied for {org.name}: {e}")
                                raise RuntimeError(f"FATAL: CloudZero API permission denied for {org.name}. Cannot proceed with connection recreation without proper API access: {e}") from e
                            else:
                                # Other errors can be treated as partial failures
                                self.logger.error(f"Failed to create connection for {provider}: {e}")
                                result.status = "partial"
                                if not result.error_message:
                                    result.error_message = f"Failed to create some connections: {e}"
            else:
                self.logger.info(f"No connections were deleted, so none need to be recreated")
            
            duration = (datetime.now() - start_time).total_seconds()
            result.duration_seconds = duration
            
            self.logger.info(f"Connection recreation for {org.name} completed with status: {result.status} (took {duration:.2f}s)")
            
        duration = (datetime.now() - start_time).total_seconds()
        result.duration_seconds = duration
        
        self.logger.info(f"Connection recreation for {org.name} completed with status: {result.status} (took {duration:.2f}s)")
        
        return result
    
    def generate_recreation_plan(self, organizations: List[Organization]) -> Dict[str, Any]:
        """
        Generate a plan showing what would be deleted/recreated.
        
        Args:
            organizations: List of organizations to analyze
            
        Returns:
            Dictionary with recreation plan details
        """
        plan = {
            "organizations": [],
            "total_connections": 0,
            "total_folders": 0,
            "total_objects": 0,
            "total_size": 0,
            "estimated_duration_minutes": 0
        }
        
        for org in organizations:
            org_plan = {
                "name": org.name,
                "connections": [],
                "folders": [],
                "folder_impact": {}
            }
            
            # Analyze connections by auto-discovering existing ones
            # Use CloudZero API to find existing connections (requires API initialization)
            try:
                self.logger.info(f"Initializing CloudZero API for {org.name} with env var: {org.api_token_env}")
                cz_client = CloudZeroAPI(org.api_token_env)
                
                self.logger.info(f"Searching for connections across {len(org.providers)} providers: {org.providers}")
                
                for provider in org.providers:
                    try:
                        self.logger.info(f"Looking for connection for provider: {provider}")
                        # Find existing connection for this provider
                        existing_connection = cz_client.find_enabled_bucket_connection(provider)
                        
                        if existing_connection:
                            conn_id = existing_connection['id']
                            conn_name = existing_connection['name']
                            
                            self.logger.info(f"Found existing connection: {conn_name} ({conn_id}) for provider {provider}")
                            
                            org_plan["connections"].append({
                                "id": conn_id,
                                "name": conn_name,
                                "provider": provider,
                                "action": "delete_and_recreate"
                            })
                            plan["total_connections"] += 1
                        else:
                                self.logger.info(f"No existing connection found for provider: {provider}")
                    except Exception as provider_e:
                        error_str = str(provider_e)
                        # Check for permission errors that should cause immediate failure
                        if "403" in error_str or "not authorized" in error_str.lower():
                            result.status = "failed"
                            result.error_message = f"FATAL: Insufficient CloudZero API permissions: {provider_e}"
                            self.logger.error(f"FATAL: CloudZero API permission denied for {org.name}: {provider_e}")
                            raise RuntimeError(f"FATAL: CloudZero API permission denied for {org.name}. Cannot proceed with connection recreation without proper API access: {provider_e}") from provider_e
                        else:
                            # Other errors can be treated as partial failures
                            self.logger.error(f"Exception finding connection for {provider}: {provider_e}")
                            result.status = "partial"
                            if not result.error_message:
                                result.error_message = f"Failed to process connections: {provider_e}"
                        
            except Exception as e:
                error_str = str(e)
                # Check for permission errors that should cause planning to fail
                if "403" in error_str or "not authorized" in error_str.lower():
                    self.logger.error(f"FATAL: CloudZero API permission denied during planning for {org.name}: {e}")
                    # For planning phase, we won't raise here since it's just for display
                    # The actual recreation will fail fast when attempted
                else:
                    # Other API failures during planning are logged but don't fail the plan
                    self.logger.error(f"Could not discover connections for {org.name}: {e}")
                    import traceback
                    self.logger.error(f"Traceback: {traceback.format_exc()}")
                # Plan will show 0 connections, which is accurate if we can't discover them
            
            # Analyze S3 folders
            # org.providers is a list, not a dict
            org_providers = [(org.name, provider) for provider in org.providers]
            if org_providers:
                folder_impact = self.folder_manager.estimate_deletion_impact(org_providers)
                org_plan["folder_impact"] = folder_impact
                
                plan["total_objects"] += folder_impact["total_objects"]
                plan["total_size"] += folder_impact["total_size"]
                plan["estimated_duration_minutes"] += folder_impact["estimated_minutes"]
                
                for detail in folder_impact["folder_details"]:
                    org_plan["folders"].append({
                        "provider": detail["provider"],
                        "prefix": detail["prefix"],
                        "objects": detail["object_count"],
                        "size": detail["total_size"],
                        "size_formatted": self.folder_manager.format_size(detail["total_size"])
                    })
                    plan["total_folders"] += 1
            
            plan["organizations"].append(org_plan)
        
        # Add summary formatting
        plan["total_size_formatted"] = self.folder_manager.format_size(plan["total_size"])
        plan["estimated_duration_minutes"] = max(plan["estimated_duration_minutes"], 1)  # Minimum 1 minute
        
        return plan
    
    def format_recreation_summary(self, results: List[ConnectionRecreationResult]) -> Dict[str, Any]:
        """
        Format recreation results into a summary.
        
        Args:
            results: List of ConnectionRecreationResult
            
        Returns:
            Formatted summary dictionary
        """
        summary = {
            "total_orgs": len(results),
            "successful_orgs": len([r for r in results if r.status == "success"]),
            "partial_orgs": len([r for r in results if r.status == "partial"]),
            "failed_orgs": len([r for r in results if r.status == "failed"]),
            "total_connections_deleted": sum(len(r.deleted_connections) for r in results),
            "total_connections_created": sum(len(r.created_connections) for r in results),
            "total_folders_processed": sum(len(r.deleted_folders) for r in results),
            "total_objects_deleted": sum(sum(f.objects_deleted for f in r.deleted_folders) for r in results),
            "total_size_deleted": sum(sum(f.total_size for f in r.deleted_folders) for r in results),
            "total_duration_seconds": sum(r.duration_seconds for r in results),
            "details": results
        }
        
        summary["total_size_formatted"] = self.folder_manager.format_size(summary["total_size_deleted"])
        summary["overall_status"] = "success" if summary["failed_orgs"] == 0 else "partial" if summary["successful_orgs"] > 0 else "failed"
        
        return summary