"""
Month processor for metadata stage.

Orchestrates month-by-month processing with comprehensive error handling and validation.
"""

import logging
from pathlib import Path
from typing import Dict, List, Optional, Tuple

import polars as pl
from rich.console import Console
from rich.progress import Progress, SpinnerColumn, TextColumn, BarColumn, TimeElapsedColumn

from ..config.models import MetadataConfig
from ..config.profiles import ProfileConfig
from ...services.s3_data_service import S3DataService
from .validation_service import ValidationService


logger = logging.getLogger(__name__)


class MonthProcessor:
    """Orchestrates month-by-month metadata processing."""
    
    def __init__(self, config: MetadataConfig, profile_config: ProfileConfig, console: Console, force: bool = False):
        """
        Initialize month processor.
        
        Args:
            config: Metadata configuration
            profile_config: Profile configuration
            console: Rich console for output
            force: Whether to force reprocessing of existing data
        """
        self.config = config
        self.profile_config = profile_config
        self.console = console
        self.force = force
        
        # Initialize services
        self.data_service = S3DataService()
        self.validation_service = ValidationService()
        
        # Import MetadataProcessor locally to avoid circular imports
        from ..processor import MetadataProcessor
        self.metadata_processor = MetadataProcessor(profile_config)
        
        # Processing statistics
        self.stats = {
            'total_months': 0,
            'processed_months': 0,
            'failed_months': 0,
            'skipped_months': 0,
            'total_rows_processed': 0,
            'errors': []
        }
    
    def process_month(self, provider: str, month: str) -> Dict[str, any]:
        """
        Process metadata allocation for a single provider/month.
        
        Args:
            provider: Cloud provider name
            month: Month in YYYY-MM format
            
        Returns:
            Dictionary with processing results
        """
        result = {
            'provider': provider,
            'month': month,
            'status': 'success',
            'rows_processed': 0,
            'validation_results': None,
            'error': None
        }
        
        try:
            # Check if already exists (skip check if force flag is set)
            if not self.force and self.data_service.check_metadata_existing_data(self.config.dataset_name, provider, month):
                self.console.print(f"  ⏭️  Skipping {provider}/{month} - already exists")
                result['status'] = 'skipped'
                self.stats['skipped_months'] += 1
                return result
            
            if self.force:
                self.console.print(f"  🔄 Processing {provider}/{month} (force mode - overwriting existing data)...")
            else:
                self.console.print(f"  🔄 Processing {provider}/{month}...")
            
            # 1. Load input data
            input_data = self.data_service.load_metadata_month_data(self.config.dataset_name, provider, month)
            result['rows_processed'] = input_data.height
            
            # 2. Validate input schema
            input_errors = self.validation_service.validate_input_schema(input_data)
            if input_errors:
                error_msg = f"Input validation failed: {input_errors}"
                result['status'] = 'failed'
                result['error'] = error_msg
                self.stats['errors'].append(f"{provider}/{month}: {error_msg}")
                return result
            
            # 3. Apply complete metadata processing (includes allocation, Azure, K8s, all processing)
            self.console.print(f"    🏷️  Applying metadata processing...")
            
            processed_data = self.metadata_processor.process_metadata(input_data, self.config)
            
            # 6. Validate post-processing
            validation_results = self.validation_service.validate_post_processing(processed_data, provider)
            result['validation_results'] = validation_results
            
            # Check for validation errors
            if validation_results.get('errors'):
                error_msg = f"Post-processing validation failed: {validation_results['errors']}"
                result['status'] = 'failed'
                result['error'] = error_msg
                self.stats['errors'].append(f"{provider}/{month}: {error_msg}")
                return result
            
            # 7. Save processed data
            self.data_service.save_metadata_month_data(self.config.dataset_name, provider, month, processed_data)
            
            # 8. Save validation report
            self._save_validation_report(validation_results, provider, month)
            
            # Update statistics
            self.stats['processed_months'] += 1
            self.stats['total_rows_processed'] += processed_data.height
            
            self.console.print(f"  ✅ Completed {provider}/{month}: {processed_data.height:,} rows")
            
        except Exception as e:
            result['status'] = 'failed'
            result['error'] = str(e)
            self.stats['errors'].append(f"{provider}/{month}: {str(e)}")
            self.stats['failed_months'] += 1
            logger.error(f"Failed to process {provider}/{month}: {e}")
        
        return result
    
    def process_all_months(self, target_month: Optional[str] = None, target_provider: Optional[str] = None) -> Dict[str, any]:
        """
        Process metadata allocation for all available months.
        
        Args:
            target_month: Specific month to process (optional)
            target_provider: Specific provider to process (optional)
            
        Returns:
            Dictionary with processing summary
        """
        # Get available months
        available_months = self.data_service.list_metadata_available_months(self.config.dataset_name)
        
        if not available_months:
            self.console.print("❌ [bold red]No input data found[/bold red]")
            return self.stats
        
        # Filter by target month/provider if specified
        if target_month:
            available_months = [(p, m) for p, m in available_months if m == target_month]
        
        if target_provider:
            available_months = [(p, m) for p, m in available_months if p == target_provider]
        
        if not available_months:
            filter_desc = f"month={target_month}" if target_month else ""
            filter_desc += f" provider={target_provider}" if target_provider else ""
            self.console.print(f"❌ [bold red]No input data found for filters: {filter_desc}[/bold red]")
            return self.stats
        
        self.stats['total_months'] = len(available_months)
        self.console.print(f"📅 Processing {len(available_months)} provider/month combinations")
        
        # Process each month with progress bar
        with Progress(
            SpinnerColumn(),
            TextColumn("[progress.description]{task.description}"),
            BarColumn(),
            TextColumn("[progress.percentage]{task.percentage:>3.0f}%"),
            TimeElapsedColumn(),
            console=self.console,
            transient=False
        ) as progress:
            
            task = progress.add_task("Processing months...", total=len(available_months))
            
            for provider, month in available_months:
                progress.update(task, description=f"Processing {provider}/{month}")
                
                result = self.process_month(provider, month)
                
                # Implement fail-fast behavior - stop immediately on first failure
                if result['status'] == 'failed':
                    self.console.print(f"\n❌ [bold red]PROCESSING STOPPED: Failure in {provider}/{month}[/bold red]")
                    self.console.print(f"💡 [yellow]Error: {result.get('error', 'Unknown error')}[/yellow]")
                    self.console.print(f"🛑 [red]Fix the error above before continuing with other months[/red]")
                    break  # Exit the processing loop immediately
                
                # Print validation summary
                if result['validation_results']:
                    self.validation_service.print_validation_summary(
                        result['validation_results'], provider, month
                    )
                
                progress.advance(task)
        
        # Create success marker if all processed successfully
        if self.stats['processed_months'] > 0 and self.stats['failed_months'] == 0:
            self._write_success_marker()
        
        return self.stats
    
    def _write_success_marker(self) -> None:
        """Write standardized SUCCESS marker after all months processed successfully."""
        from ...services.success_marker_service import SuccessMarkerService, create_processing_summary, create_validation_summary
        
        # Create standardized processing summary
        processing_summary = create_processing_summary(
            total_items=self.stats['total_months'],
            processed_items=self.stats['processed_months'],
            failed_items=self.stats['failed_months'],
            additional_metrics={
                "total_providers": len(self.stats.get('providers_processed', [])),
                "allocation_type": "hybrid_v1_deterministic"
            }
        )
        
        # Create validation summary (Metadata has validation)
        validation_summary = create_validation_summary(
            validation_performed=True,
            validation_passed=True,  # Only written if validation passed
            total_validations=2,  # Basic validation + profile validation
            failed_validations=0,
            validation_details={
                "profile_validation_passed": True,
                "metadata_allocation_validated": True,
                "cross_month_consistency_maintained": True
            }
        )
        
        # Use standardized success marker service
        success_marker_service = SuccessMarkerService(self.data_service)
        success = success_marker_service.create_success_marker(
            dataset_name=self.config.dataset_name,
            stage="metadata",
            processing_summary=processing_summary,
            config={
                "dataset_name": self.config.dataset_name,
                "majority_regions": self.config.majority_regions,
                "majority_environment": self.config.majority_environment,
                "base_allocation": self.config.base_allocation
            },
            validation_summary=validation_summary,
            additional_metadata={
                "profile_config_source": "s3://bucket/czbillgen/metadata_profiles/metadata_profiles.yaml",
                "allocation_strategy": "v1_hybrid_deterministic"
            }
        )
        
        if success:
            self.console.print("✅ [green]Metadata SUCCESS marker written[/green]")
        else:
            self.console.print("⚠️  [yellow]Failed to write metadata SUCCESS marker[/yellow]")
    
    def _save_validation_report(self, validation_results: Dict, provider: str, month: str) -> None:
        """
        Save validation report to local file.
        
        Args:
            validation_results: Validation results dictionary
            provider: Cloud provider name
            month: Month in YYYY-MM format
        """
        try:
            # Create validation reports directory
            reports_dir = Path(f"/tmp/metadata_validation_reports/{self.config.dataset_name}")
            reports_dir.mkdir(parents=True, exist_ok=True)
            
            # Save validation report
            report_path = reports_dir / f"{provider}_{month}_validation.txt"
            self.validation_service.save_validation_report(
                validation_results, provider, month, str(report_path)
            )
            
        except Exception as e:
            logger.warning(f"Failed to save validation report for {provider}/{month}: {e}")
    
    def print_final_summary(self) -> None:
        """Print final processing summary."""
        self.console.print("\n" + "="*60)
        self.console.print("📊 [bold cyan]Metadata Processing Summary[/bold cyan]")
        self.console.print("="*60)
        
        self.console.print(f"📅 Total months: {self.stats['total_months']}")
        self.console.print(f"✅ Processed: {self.stats['processed_months']}")
        self.console.print(f"⏭️  Skipped: {self.stats['skipped_months']}")
        self.console.print(f"❌ Failed: {self.stats['failed_months']}")
        self.console.print(f"📊 Total rows: {self.stats['total_rows_processed']:,}")
        
        if self.stats['errors']:
            self.console.print(f"\n❌ [bold red]Errors ({len(self.stats['errors'])}):[/bold red]")
            for error in self.stats['errors'][:5]:  # Show first 5 errors
                self.console.print(f"  • {error}")
            if len(self.stats['errors']) > 5:
                self.console.print(f"  • ... and {len(self.stats['errors']) - 5} more")
        
        # Final status
        if self.stats['failed_months'] == 0 and self.stats['processed_months'] > 0:
            self.console.print("\n🎉 [bold green]Metadata allocation completed successfully![/bold green]")
        elif self.stats['processed_months'] > 0:
            self.console.print(f"\n⚠️  [yellow]Metadata allocation completed with {self.stats['failed_months']} failures[/yellow]")
        else:
            self.console.print("\n❌ [red]No data processed[/red]")
    
    def get_stats(self) -> Dict[str, any]:
        """Get processing statistics."""
        return self.stats.copy()
    
