"""
3-Tier Dry Run System - "Dry Run First" Architecture

Every deployment is validated through 3 tiers:
- Tier 1: Local validation (~100ms) - Syntax, imports, config
- Tier 2: Railpack plan (~1-2s) - Build plan generation
- Tier 3: E2B Sandbox (~30-60s) - Full build validation (smart detection)

This ensures deployments never fail due to avoidable errors.
"""

from pathlib import Path
from typing import Optional
from dataclasses import dataclass, field
from enum import Enum

from .base import BuildPlan
from .validation import validate_project, ValidationResult
from .e2b import get_sandbox, SandboxResult
from .cache import get_detector
from .factory import get_factory


class TierStatus(Enum):
    """Status of a tier validation."""
    PENDING = "pending"
    RUNNING = "running"
    PASSED = "passed"
    FAILED = "failed"
    SKIPPED = "skipped"


@dataclass
class DryRunResult:
    """Complete result of dry-run validation."""
    success: bool
    tier1: ValidationResult
    tier2: Optional[BuildPlan]
    tier3: Optional[SandboxResult]
    tier3_ran: bool
    tier3_reason: str
    errors: list[str] = field(default_factory=list)
    
    @property
    def all_tiers_passed(self) -> bool:
        """Check if all executed tiers passed."""
        if not self.tier1.success:
            return False
        if self.tier2 is None:
            return False
        if self.tier3_ran and (self.tier3 is None or not self.tier3.success):
            return False
        return True
    
    def get_summary(self) -> str:
        """Get human-readable summary."""
        lines = ["Dry Run Results:", ""]
        
        # Tier 1
        t1_status = "✅ PASSED" if self.tier1.success else "❌ FAILED"
        lines.append(f"Tier 1 (Local): {t1_status}")
        if self.tier1.errors:
            for err in self.tier1.errors:
                lines.append(f"  - {err}")
        
        # Tier 2
        if self.tier2:
            lines.append(f"Tier 2 (Railpack): ✅ PASSED - {self.tier2.framework}")
        else:
            lines.append("Tier 2 (Railpack): ❌ FAILED")
        
        # Tier 3
        if self.tier3_ran:
            if self.tier3 and self.tier3.success:
                lines.append(f"Tier 3 (Sandbox): ✅ PASSED ({self.tier3.build_time_seconds:.1f}s)")
            else:
                lines.append("Tier 3 (Sandbox): ❌ FAILED")
                if self.tier3 and self.tier3.error_message:
                    lines.append(f"  - {self.tier3.error_message}")
        else:
            lines.append(f"Tier 3 (Sandbox): ⏭️ SKIPPED - {self.tier3_reason}")
        
        return "\n".join(lines)


class DryRunEngine:
    """
    3-Tier Dry Run Engine.
    
    Validates deployments through increasingly thorough checks,
    ensuring builds succeed before touching real infrastructure.
    """
    
    def __init__(self, project_path: Path, api_client=None, file_manifest=None):
        self.project_path = project_path
        self.file_manifest = file_manifest
        self.factory = get_factory()
        self.sandbox = get_sandbox(api_client)
        self.detector = get_detector(project_path)
    
    def run(
        self,
        force_sandbox: bool = False,
        skip_sandbox: bool = False
    ) -> DryRunResult:
        """
        Run full dry-run validation.
        
        Args:
            force_sandbox: Always run Tier 3 even if not needed
            skip_sandbox: Never run Tier 3 (for quick iteration)
            
        Returns:
            DryRunResult with all tier results
        """
        errors = []
        
        # ========== TIER 1: Local Validation ==========
        tier1_result = validate_project(self.project_path)
        
        if not tier1_result.success:
            return DryRunResult(
                success=False,
                tier1=tier1_result,
                tier2=None,
                tier3=None,
                tier3_ran=False,
                tier3_reason="Skipped due to Tier 1 failures",
                errors=tier1_result.errors
            )
        
        # ========== TIER 2: Railpack Plan ==========
        try:
            tier2_plan = self.factory.get_build_plan(self.project_path)
        except Exception as e:
            errors.append(f"Railpack plan generation failed: {e}")
            return DryRunResult(
                success=False,
                tier1=tier1_result,
                tier2=None,
                tier3=None,
                tier3_ran=False,
                tier3_reason="Skipped due to Tier 2 failure",
                errors=errors
            )
        
        # ========== TIER 3: E2B Sandbox ==========
        tier3_result: Optional[SandboxResult] = None
        tier3_ran = False
        tier3_reason = ""
        
        if skip_sandbox:
            tier3_reason = "Skipped by user (--skip-sandbox)"
        else:
            # Check if we should run sandbox
            should_run, reason = self.detector.should_run_sandbox(
                tier2_plan, 
                force=force_sandbox
            )
            tier3_reason = reason
            
            if should_run and self.sandbox.is_available:
                tier3_ran = True
                tier3_result = self.sandbox.validate_build(
                    self.project_path,
                    tier2_plan,
                    file_manifest=self.file_manifest or []
                )
                
                # Record result for smart detection
                if tier3_result.success:
                    self.detector.record_success(tier2_plan)
                else:
                    self.detector.record_failure(tier2_plan)
                    errors.append(
                        tier3_result.error_message or "Sandbox build failed"
                    )
            elif should_run and not self.sandbox.is_available:
                tier3_reason = "Sandbox unavailable (not authenticated)"
            
        # Determine overall success
        success = (
            tier1_result.success and
            tier2_plan is not None and
            (not tier3_ran or (tier3_result and tier3_result.success))
        )
        
        return DryRunResult(
            success=success,
            tier1=tier1_result,
            tier2=tier2_plan,
            tier3=tier3_result,
            tier3_ran=tier3_ran,
            tier3_reason=tier3_reason,
            errors=errors
        )
    
    def quick_check(self) -> ValidationResult:
        """
        Run only Tier 1 validation for quick feedback.
        
        Returns:
            ValidationResult from local validation
        """
        return validate_project(self.project_path)
    
    def generate_plan(self) -> BuildPlan:
        """
        Generate build plan (Tier 2).
        
        Returns:
            BuildPlan from Railpack analysis
        """
        return self.factory.get_build_plan(self.project_path)


def run_dry_run(
    project_path: Path,
    force_sandbox: bool = False,
    skip_sandbox: bool = False,
    api_client=None,
    file_manifest: list = None
) -> DryRunResult:
    """
    Convenience function to run dry-run validation.
    
    Args:
        project_path: Path to project directory
        force_sandbox: Always run sandbox
        skip_sandbox: Skip sandbox validation
        api_client: Xenfra API client for Tier 3 sandbox
        file_manifest: List of file info dicts for the project
        
    Returns:
        DryRunResult with full validation results
    """
    engine = DryRunEngine(project_path, api_client=api_client, file_manifest=file_manifest)
    return engine.run(force_sandbox=force_sandbox, skip_sandbox=skip_sandbox)


def quick_validate(project_path: Path) -> ValidationResult:
    """
    Quick validation (Tier 1 only).
    
    Args:
        project_path: Path to project directory
        
    Returns:
        ValidationResult
    """
    return validate_project(project_path)
