from typing import Dict, List, Optional
"""Terminal message formatting utilities for consistent CLI communication."""

from dataclasses import dataclass
from enum import Enum


class MessageType(Enum):
    """Message type classification for consistent formatting."""

    STAGE_START = "🚀"
    SUCCESS = "✅"
    ERROR = "❌"
    WARNING = "⚠️"
    INFO = "📊"
    TECHNICAL = "🔧"
    SUGGESTION = "💡"
    UPLOAD = "🔌"
    TARGET = "🎯"
    COST = "💰"


@dataclass
class MonthlyLineItemMetrics:
    """Standardized monthly line item metrics for consistent reporting."""

    provider: str
    max_monthly: int
    min_monthly: int
    cost_tier: str
    additional_context: str = ""


class TerminalMessage:
    """Base class for consistent terminal messaging across CLI."""

    @staticmethod
    def stage_start(stage_name: str, config_summary: str) -> str:
        """Format stage initiation message."""
        return f"{MessageType.STAGE_START.value} Starting {stage_name} Stage\n   📋 Config: {config_summary}"

    @staticmethod
    def stage_complete(stage_name: str, duration: str, summary: str) -> str:
        """Format stage completion message."""
        return f"{MessageType.SUCCESS.value} {stage_name} Complete ({duration}) - {summary}"

    @staticmethod
    def monthly_line_items(metrics: MonthlyLineItemMetrics) -> str:
        """Format monthly line item reporting with max/min focus."""
        context = f" {metrics.additional_context}" if metrics.additional_context else ""
        return (
            f"{metrics.provider}: {metrics.max_monthly:,} max, {metrics.min_monthly:,} min "
            f"line items/month ({metrics.cost_tier} scale){context}"
        )

    @staticmethod
    def monthly_summary(
        metrics_list: List[MonthlyLineItemMetrics], overall_tier: str
    ) -> str:
        """Format multi-provider monthly line item summary."""
        lines = [f"{MessageType.INFO.value} Monthly Line Items Summary:"]
        for metrics in metrics_list:
            lines.append(f"   {TerminalMessage.monthly_line_items(metrics)}")
        lines.append(f"\n{MessageType.TARGET.value} Overall: {overall_tier} scale")
        return "\n".join(lines)

    @staticmethod
    def job_progress(current: int, total: int, description: str) -> str:
        """Format job-level progress indication."""
        return f"[JOB {current}/{total}] {description}..."

    @staticmethod
    def error_with_next_steps(
        stage_name: str,
        error_type: str,
        issues: List[str],
        next_steps: List[str],
        details_path: Optional[str] = None,
    ) -> str:
        """Format comprehensive error message with actionable next steps."""
        lines = [f"{MessageType.ERROR.value} {stage_name} Failed - {error_type}", ""]

        if len(issues) == 1:
            lines.extend(["🔍 Critical Issue:", f"   {issues[0]}"])
        else:
            lines.append("🔍 Issues Found:")
            for i, issue in enumerate(issues, 1):
                lines.append(f"   {i}. {issue}")

        lines.extend(["", f"{MessageType.SUGGESTION.value} Next Steps:"])
        for step in next_steps:
            lines.append(f"   • {step}")

        if details_path:
            lines.extend(["", f"📄 Full details: {details_path}"])

        return "\n".join(lines)

    @staticmethod
    def validation_success_generate(validation_results: dict) -> str:
        """Generate stage specific validation success message"""
        summary = validation_results.get("summary", {})
        cost_val = summary.get("cost_validation", {})

        return f"""✅ Generate Validation Summary (Success):
   Cost Validation: ✅ ${cost_val.get("actual", 0):,.2f} generated (expected ${cost_val.get("expected", 0):,.2f})
   Row Count: ✅ {summary.get("total_rows_validated", 0):,} billing records
   Providers: ✅ {", ".join(summary.get("providers_found", []))}
   Services: ✅ {len(summary.get("services_found", []))} unique services
   Files: ✅ {summary.get("files_validated", 0)} monthly data files

📄 Detailed report: validation/summary.txt"""

    @staticmethod
    def validation_error_generate(validation_results: dict) -> str:
        """Generate stage specific validation error message"""
        summary = validation_results.get("summary", {})
        errors = summary.get("errors", [])

        error_list = "\n".join(f"   {i + 1}. {error}" for i, error in enumerate(errors))

        return f"""❌ Generate Validation Summary (Errors):
   Row Count: ✅ {summary.get("total_rows_validated", 0):,} billing records processed
   Files Checked: ✅ {summary.get("files_validated", 0)} monthly data files
   Schema Validation: ❌
   Cost Validation: ❌
   Provider Validation: ❌
   Errors: {len(errors)} issues found

📄 Detailed report: validation/summary.txt

❌ generate Failed - Validation Errors

🔍 Issues Found:
{error_list}

💡 Next Steps:
   • Check generate stage logs for detailed error information
   • Verify parquet files were created in provider/month structure  
   • Run with --verbose for additional diagnostic output
   • Check pipeline configuration for correct cost and provider settings

📄 Full details: validation/summary.txt"""


class MonthlyLineItemReporter:
    """Handles monthly line item analysis and reporting for all pipeline contexts."""

    def __init__(self, tenant_factor: int = 1):
        self.tenant_factor = tenant_factor
        self.cost_tiers = [
            (200_000, "Demo"),
            (40_000_000, "CloudZero"),
            (500_000_000, "Large"),
            (float("inf"), "Largest"),
        ]

    def analyze_dataframe_monthly(
        self, df, stage_name: str
    ) -> List[MonthlyLineItemMetrics]:
        """Analyze DataFrame for monthly line item metrics by provider."""
        import polars as pl

        metrics_list = []

        # Group by provider and month to get monthly line item counts
        if "cloud_provider" not in df.columns or "timestamp" not in df.columns:
            return metrics_list

        monthly_analysis = (
            df.group_by(
                [
                    pl.col("cloud_provider"),
                    pl.col("timestamp").dt.strftime("%Y-%m").alias("month"),
                ]
            )
            .len()
            .rename({"len": "line_items"})
        )

        # Get max/min monthly line items per provider
        provider_monthly = monthly_analysis.group_by("cloud_provider").agg(
            [
                pl.col("line_items").max().alias("max_monthly"),
                pl.col("line_items").min().alias("min_monthly"),
            ]
        )

        for row in provider_monthly.iter_rows(named=True):
            provider = row["cloud_provider"]
            max_monthly = row["max_monthly"]
            min_monthly = row["min_monthly"]
            cost_tier = self._classify_cost_tier(max_monthly)

            metrics_list.append(
                MonthlyLineItemMetrics(
                    provider=provider,
                    max_monthly=max_monthly,
                    min_monthly=min_monthly,
                    cost_tier=cost_tier,
                )
            )

        return sorted(metrics_list, key=lambda x: x.max_monthly, reverse=True)

    def analyze_partitions_monthly(
        self, partitions: Dict[tuple, list]
    ) -> List[MonthlyLineItemMetrics]:
        """Analyze generated partitions for monthly line item metrics by provider."""

        # Build monthly line item counts from partition structure
        provider_monthly_counts = {}

        for (provider, month), dfs in partitions.items():
            if not dfs:  # Skip empty partitions
                continue

            # Calculate total line items for this provider/month
            total_line_items = sum(df.height for df in dfs if df is not None)

            if provider not in provider_monthly_counts:
                provider_monthly_counts[provider] = []
            provider_monthly_counts[provider].append(total_line_items)

        # Convert to MonthlyLineItemMetrics format
        metrics_list = []
        for provider, monthly_counts in provider_monthly_counts.items():
            if monthly_counts:  # Only process providers with data
                max_monthly = max(monthly_counts)
                min_monthly = min(monthly_counts)
                cost_tier = self._classify_cost_tier(max_monthly)

                metrics_list.append(
                    MonthlyLineItemMetrics(
                        provider=provider,
                        max_monthly=max_monthly,
                        min_monthly=min_monthly,
                        cost_tier=cost_tier,
                    )
                )

        return sorted(metrics_list, key=lambda x: x.max_monthly, reverse=True)

    def _classify_cost_tier(self, monthly_line_items: int) -> str:
        """Classify monthly line items into cost tiers."""
        for threshold, tier in self.cost_tiers:
            if monthly_line_items <= threshold:
                return tier
        return "Unknown"


class ProgressReporter:
    """Handles progress indication for long-running operations."""

    def __init__(self, total_jobs: int, verbose: bool = False):
        self.total_jobs = total_jobs
        self.verbose = verbose
        self.current_job = 0

    def start_job(self, job_name: str):
        """Report start of job with progress context."""
        self.current_job += 1
        print(TerminalMessage.job_progress(self.current_job, self.total_jobs, job_name))

    def complete_job(self, success: bool = True):
        """Report job completion."""
        status = "✅" if success else "❌"
        print(f"   {status}")

    def task_progress(
        self,
        completed: int,
        total: int,
        description: str,
        estimated_remaining: Optional[int] = None,
    ):
        """Show detailed task progress in verbose mode."""
        if not self.verbose:
            return

        percentage = int((completed / total) * 100) if total > 0 else 0
        bar_length = 20
        filled = int((percentage / 100) * bar_length)
        bar = "█" * filled + "░" * (bar_length - filled)

        progress_text = (
            f"   {description} {bar} {percentage}% ({completed:,}/{total:,})"
        )
        if estimated_remaining:
            progress_text += f" (Est: {estimated_remaining}s remaining)"

        print(progress_text)
