"""
Pruning service for append operations.

Ensures that drop pruning works correctly with appended drops,
handling both regular and append-created drops uniformly.
"""

from typing import List, Dict, Any, Optional
import boto3
from botocore.exceptions import ClientError

from src.services.s3_upload_service import S3UploadService


class AppendPruningService:
    """
    Service for pruning drops created through append operations.
    
    Single responsibility: Ensure append-created drops are properly
    included in pruning operations alongside regular drops.
    """
    
    def __init__(self, s3_upload_service: S3UploadService):
        """
        Initialize with existing S3 upload service.
        
        Args:
            s3_upload_service: Existing upload service with pruning capability
        """
        self.s3_upload_service = s3_upload_service
    
    def prune_drops_including_appends(
        self,
        organization: str,
        provider: str,
        billing_period: str,
        max_drops: int = 3
    ) -> List[str]:
        """
        Prune drops including those created through append operations.
        
        Uses the existing pruning logic but ensures append-created drops
        are properly identified and handled.
        
        Args:
            organization: Organization name
            provider: Provider name
            billing_period: Billing period
            max_drops: Maximum number of drops to keep
            
        Returns:
            List of error messages if any
        """
        print(f"    🧹 Pruning drops for {provider}/{billing_period} (including appends)")
        
        # The existing S3UploadService.prune_old_drops_for_period should handle
        # append-created drops correctly since they use the same S3 structure
        # and timestamp-based drop IDs
        
        try:
            errors = self.s3_upload_service.prune_old_drops_for_period(
                organization=organization,
                provider=provider,
                billing_period=billing_period,
                max_drops=max_drops
            )
            
            if not errors:
                print(f"    ✓ Drop pruning completed successfully")
            else:
                for error in errors:
                    print(f"    ⚠️  Pruning warning: {error}")
            
            return errors
            
        except Exception as e:
            error_msg = f"Drop pruning failed for {provider}/{billing_period}: {str(e)}"
            print(f"    ❌ {error_msg}")
            return [error_msg]
    
    def validate_append_drop_structure(
        self,
        organization: str,
        provider: str,
        billing_period: str,
        drop_id: str
    ) -> Dict[str, Any]:
        """
        Validate that append-created drop follows proper structure.
        
        Ensures the drop created through append operations has the correct
        structure and can be properly handled by existing services.
        
        Args:
            organization: Organization name
            provider: Provider name
            billing_period: Billing period
            drop_id: Drop ID to validate
            
        Returns:
            Validation results dictionary
        """
        from ..s3.uploader import S3Uploader
        from src.services.environment_service import EnvironmentService
        
        # Get S3 configuration
        env_service = EnvironmentService()
        s3_config = env_service.get_s3_config()
        
        # Create S3 uploader for structure validation
        s3_uploader = S3Uploader(
            bucket=s3_config["bucket"],
            region=s3_config["region"],
            root_folder="billing-data"
        )
        
        drop_prefix = s3_uploader.build_s3_prefix(
            organization, provider, billing_period, drop_id
        )
        
        try:
            # List files in the drop
            response = s3_uploader.s3_client.list_objects_v2(
                Bucket=s3_uploader.bucket,
                Prefix=drop_prefix
            )
            
            if 'Contents' not in response:
                return {
                    'valid': False,
                    'error': f"No files found in drop {drop_id}",
                    'drop_prefix': drop_prefix
                }
            
            # Analyze file structure
            files = []
            data_export_files = 0
            
            for obj in response['Contents']:
                key = obj['Key']
                filename = key.split('/')[-1]
                files.append(filename)
                
                if filename.startswith('data-export-') and filename.endswith('.csv.gz'):
                    data_export_files += 1
            
            # Validation checks
            issues = []
            
            if data_export_files == 0:
                issues.append("No data-export files found")
            
            # Check for proper sequence numbering
            if data_export_files > 1:
                sequences = []
                for filename in files:
                    if filename.startswith('data-export-'):
                        try:
                            seq = int(filename[12:16])  # Extract NNNN part
                            sequences.append(seq)
                        except (ValueError, IndexError):
                            issues.append(f"Invalid sequence number in {filename}")
                
                sequences.sort()
                # Check for gaps in sequence
                if sequences and sequences[-1] - sequences[0] + 1 != len(sequences):
                    issues.append("Gaps in sequence numbering detected")
            
            return {
                'valid': len(issues) == 0,
                'issues': issues,
                'drop_prefix': drop_prefix,
                'total_files': len(files),
                'data_export_files': data_export_files,
                'files': files
            }
            
        except ClientError as e:
            return {
                'valid': False,
                'error': f"Failed to validate drop structure: {str(e)}",
                'drop_prefix': drop_prefix
            }
    
    def cleanup_failed_append_operations(
        self,
        organization: str,
        provider: str,
        billing_period: str,
        failed_drop_ids: List[str]
    ) -> Dict[str, Any]:
        """
        Clean up partially created drops from failed append operations.
        
        Removes incomplete drops that were created during failed append operations
        to prevent them from interfering with future operations.
        
        Args:
            organization: Organization name
            provider: Provider name
            billing_period: Billing period
            failed_drop_ids: List of drop IDs to clean up
            
        Returns:
            Cleanup results
        """
        print(f"    🧽 Cleaning up {len(failed_drop_ids)} failed append drops")
        
        cleaned_drops = []
        cleanup_errors = []
        
        from ..s3.uploader import S3Uploader
        from src.services.environment_service import EnvironmentService
        
        # Get S3 configuration
        env_service = EnvironmentService()
        s3_config = env_service.get_s3_config()
        
        s3_uploader = S3Uploader(
            bucket=s3_config["bucket"],
            region=s3_config["region"], 
            root_folder="billing-data"
        )
        
        for drop_id in failed_drop_ids:
            try:
                drop_prefix = s3_uploader.build_s3_prefix(
                    organization, provider, billing_period, drop_id
                )
                
                # List all objects in the drop
                response = s3_uploader.s3_client.list_objects_v2(
                    Bucket=s3_uploader.bucket,
                    Prefix=drop_prefix
                )
                
                if 'Contents' not in response:
                    print(f"    ℹ️  Drop {drop_id} already clean (no objects found)")
                    continue
                
                # Delete all objects in the drop
                objects_to_delete = [{'Key': obj['Key']} for obj in response['Contents']]
                
                if objects_to_delete:
                    s3_uploader.s3_client.delete_objects(
                        Bucket=s3_uploader.bucket,
                        Delete={'Objects': objects_to_delete}
                    )
                    
                    cleaned_drops.append(drop_id)
                    print(f"    ✓ Cleaned {len(objects_to_delete)} objects from drop {drop_id}")
                
            except ClientError as e:
                error_msg = f"Failed to clean drop {drop_id}: {str(e)}"
                cleanup_errors.append(error_msg)
                print(f"    ❌ {error_msg}")
        
        return {
            'cleaned_drops': cleaned_drops,
            'cleanup_errors': cleanup_errors,
            'total_cleaned': len(cleaned_drops)
        }