"""Console reporter using rich library for beautiful CLI output."""

from rich import box
from rich.console import Console
from rich.panel import Panel
from rich.table import Table
from rich.text import Text

from ..models.report import ImpactReport


class ConsoleReporter:
    """
    Generates formatted console output for impact reports using rich library.
    """

    def __init__(self, console: Console | None = None):
        """
        Initialize the console reporter.

        Args:
            console: Optional rich Console instance (creates new one if not provided)
        """
        self.console = console or Console()

    def report(self, impact: ImpactReport, show_details: bool = True) -> None:
        """
        Print a complete impact analysis report to the console.

        Args:
            impact: ImpactReport to display
            show_details: Whether to show detailed denial list (default: True)
        """
        self._print_header()
        self._print_summary(impact)
        self._print_risk_assessment(impact)
        self._print_simulation_warnings(impact)

        if impact.has_denials:
            self._print_denied_services(impact)
            self._print_top_denied_actions(impact)
            self._print_affected_principals(impact)

            if show_details:
                self._print_denial_details(impact, limit=20)

        self._print_recommendations(impact)

    def _print_header(self) -> None:
        """Print the report header."""
        title = Text("SCP Impact Analysis Report", style="bold cyan")
        self.console.print(Panel(title, box=box.DOUBLE, border_style="cyan"))
        self.console.print()

    def _print_summary(self, impact: ImpactReport) -> None:
        """Print summary statistics."""
        self.console.print("[bold]Summary[/bold]", style="cyan")
        self.console.print("-" * 60)

        # Format numbers with commas
        total = f"{impact.total_events:,}"
        allowed = f"{impact.allowed_count:,}"
        denied = f"{impact.denied_count:,}"

        allowed_pct = (
            (impact.allowed_count / impact.total_events * 100) if impact.total_events > 0 else 0
        )
        denied_pct = impact.denial_rate

        self.console.print(f"Total Events Analyzed:     {total}")
        self.console.print(
            f"[green]+ Would Be Allowed:[/green]       {allowed} ({allowed_pct:.1f}%)"
        )

        # Color denied count based on severity
        denied_color = "green" if denied_pct < 1 else "yellow" if denied_pct < 5 else "red"

        # Add confidence qualifier when unevaluable conditions exist
        qualifier = impact.statistics.confidence_qualifier
        if qualifier == "lower-bound":
            unevaluable_count = len(impact.statistics.unevaluable_keys_summary)
            self.console.print(
                f"[{denied_color}]X Would Be DENIED:[/{denied_color}]  "
                f"{denied} (>={denied_pct:.1f}% -- lower bound, "
                f"{unevaluable_count} unevaluable condition key(s))"
            )
        else:
            self.console.print(
                f"[{denied_color}]X Would Be DENIED:[/{denied_color}]  "
                f"{denied} ({denied_pct:.1f}% -- all conditions fully evaluated)"
            )

        # Show filtered event counts
        slr = impact.statistics.slr_events_filtered
        mgmt = impact.statistics.mgmt_account_events_filtered
        if slr > 0 or mgmt > 0:
            self.console.print()
            if slr > 0:
                self.console.print(
                    f"  Filtered: {slr:,} service-linked role event(s) "
                    "(SCPs do not apply to SLRs)",
                    style="dim",
                )
            if mgmt > 0:
                self.console.print(
                    f"  Filtered: {mgmt:,} management account event(s) "
                    "(SCPs do not apply to management account)",
                    style="dim",
                )

        self.console.print()

        # Analysis period
        start = impact.start_time.strftime("%Y-%m-%d %H:%M")
        end = impact.end_time.strftime("%Y-%m-%d %H:%M")
        self.console.print(f"Analysis Period:           {start} to {end}")

        # Policy info
        if impact.scp_policy_name:
            self.console.print(f"SCP Policy:                {impact.scp_policy_name}")

        self.console.print()

    def _print_risk_assessment(self, impact: ImpactReport) -> None:
        """Print risk assessment."""
        risk_level = impact.get_risk_level()

        # Color code risk level
        risk_colors = {
            "NONE": "green",
            "LOW": "green",
            "MEDIUM": "yellow",
            "HIGH": "red",
            "CRITICAL": "bold red",
        }
        color = risk_colors.get(risk_level, "white")

        self.console.print(f"[bold]Risk Assessment:[/bold] [{color}]{risk_level}[/{color}]")

        # Additional context
        if risk_level == "NONE":
            self.console.print("  No events would be denied by this SCP.", style="green")
        elif risk_level == "LOW":
            self.console.print(
                f"  Only {impact.denied_count} denial(s) detected. "
                "Minimal production impact expected.",
                style="green",
            )
        elif risk_level == "MEDIUM":
            self.console.print(
                f"  {impact.denied_count} denials detected. Review carefully before applying.",
                style="yellow",
            )
        elif risk_level in ("HIGH", "CRITICAL"):
            self.console.print(
                f"  WARNING:  {impact.denied_count} denials detected! "
                "This SCP may significantly impact operations.",
                style="red bold",
            )

        # Critical services warning
        if impact.statistics.critical_services_affected:
            services = ", ".join(impact.statistics.critical_services_affected)
            self.console.print(
                f"  WARNING:  Critical services affected: {services}",
                style="yellow bold",
            )

        self.console.print()

    def _print_simulation_warnings(self, impact: ImpactReport) -> None:
        """Print simulation confidence and warnings."""
        stats = impact.statistics
        confidence = stats.simulation_confidence
        has_warnings = (
            stats.unevaluable_keys_summary or stats.unresolved_resource_count > 0 or impact.warnings
        )

        if not has_warnings and confidence == "HIGH":
            return  # No warnings to show

        # Confidence level colors
        confidence_colors = {
            "HIGH": "green",
            "MEDIUM": "yellow",
            "LOW": "red",
        }
        color = confidence_colors.get(confidence, "white")

        self.console.print(f"[bold]Simulation Confidence:[/bold] [{color}]{confidence}[/{color}]")
        self.console.print("-" * 60)

        # Resource resolution rate
        if stats.total_evaluated_events > 0:
            resolved = stats.total_evaluated_events - stats.unresolved_resource_count
            rate = stats.resource_resolution_rate
            rate_color = "green" if rate >= 95 else "yellow" if rate >= 80 else "red"
            self.console.print(
                f"  Resource ARN resolved: {resolved:,}/{stats.total_evaluated_events:,} "
                f"events ([{rate_color}]{rate:.1f}%[/{rate_color}])"
            )

        # Unevaluable condition keys
        if stats.unevaluable_keys_summary:
            self.console.print()
            self.console.print("  Unevaluable condition keys encountered:", style="yellow")
            # Sort by frequency
            sorted_keys = sorted(
                stats.unevaluable_keys_summary.items(),
                key=lambda x: x[1],
                reverse=True,
            )
            for key, count in sorted_keys[:5]:  # Top 5
                self.console.print(f"    - {key} (found in {count:,} evaluations)")

            if len(sorted_keys) > 5:
                remaining = len(sorted_keys) - 5
                self.console.print(f"    ... and {remaining} more keys", style="dim")

            self.console.print()
            self.console.print(
                "  WARNING: These conditions were assumed to MATCH (not deny).",
                style="yellow",
            )
            self.console.print(
                "  The actual denial rate may be HIGHER than reported.",
                style="yellow",
            )
            self.console.print(
                "  Supply a --context file to resolve evaluable keys, or use",
                style="dim",
            )
            self.console.print(
                "  --strict-conditions to treat unevaluable conditions as denials (worst-case).",
                style="dim",
            )

        # Data event and other warnings
        if impact.warnings:
            self.console.print()
            for warning in impact.warnings:
                self.console.print(f"  [yellow]WARNING:[/yellow] {warning}")

        self.console.print()

    def _print_denied_services(self, impact: ImpactReport) -> None:
        """Print denied actions grouped by service."""
        if not impact.statistics.denied_by_service:
            return

        self.console.print("[bold]Denied Actions by Service[/bold]", style="cyan")
        self.console.print("-" * 60)

        # Sort by count descending
        services = sorted(
            impact.statistics.denied_by_service.items(),
            key=lambda x: x[1],
            reverse=True,
        )

        for service, count in services[:10]:  # Top 10 services
            # Highlight critical services
            if service in {"iam", "sts", "kms", "cloudtrail"}:
                self.console.print(
                    f"  {service:20} {count:>8,} denials [yellow](critical)[/yellow]"
                )
            else:
                self.console.print(f"  {service:20} {count:>8,} denials")

        self.console.print()

    def _print_top_denied_actions(self, impact: ImpactReport) -> None:
        """Print top denied actions."""
        top_actions = impact.get_top_denied_actions(limit=10)

        if not top_actions:
            return

        self.console.print("[bold]Top 10 Denied Actions[/bold]", style="cyan")
        self.console.print("-" * 60)

        for i, (action, count) in enumerate(top_actions, 1):
            percentage = (count / impact.denied_count * 100) if impact.denied_count > 0 else 0
            self.console.print(f"  {i:2}. {action:50} {count:>6,} ({percentage:>5.1f}%)")

        self.console.print()

    def _print_affected_principals(self, impact: ImpactReport) -> None:
        """Print affected principals."""
        top_principals = impact.get_top_affected_principals(limit=10)

        if not top_principals:
            return

        self.console.print("[bold]Top 10 Affected Principals[/bold]", style="cyan")
        self.console.print("-" * 60)

        for arn, count in top_principals:
            # Truncate long ARNs
            display_arn = arn if len(arn) <= 70 else arn[:67] + "..."
            self.console.print(f"  {display_arn:70} {count:>6,} denials")

        self.console.print()

    def _print_denial_details(self, impact: ImpactReport, limit: int = 20) -> None:
        """Print detailed denial information in a table."""
        if not impact.denied_events:
            return

        self.console.print(f"[bold]Denial Details (showing first {limit})[/bold]", style="cyan")

        table = Table(box=box.SIMPLE)
        table.add_column("Time", style="dim")
        table.add_column("Action", style="yellow")
        table.add_column("Principal", style="cyan", max_width=40)
        table.add_column("SCP Statement", style="magenta")
        table.add_column("Reason", style="red", max_width=30)

        for event, result in impact.denied_events[:limit]:
            time_str = event.event_time.strftime("%m-%d %H:%M:%S")
            action = event.iam_action
            principal = event.principal_arn or "Unknown"
            if len(principal) > 40:
                principal = principal[:37] + "..."

            statement = (
                result.matched_statement.sid
                if result.matched_statement and result.matched_statement.sid
                else "N/A"
            )
            reason = result.reason

            table.add_row(time_str, action, principal, statement, reason)

        self.console.print(table)
        self.console.print()

        if len(impact.denied_events) > limit:
            remaining = len(impact.denied_events) - limit
            self.console.print(f"  ... and {remaining:,} more denials", style="dim")
            self.console.print()

    def _print_recommendations(self, impact: ImpactReport) -> None:
        """Print recommendations based on the analysis."""
        self.console.print("[bold]Recommendations[/bold]", style="cyan")
        self.console.print("-" * 60)

        risk_level = impact.get_risk_level()

        if risk_level == "NONE":
            self.console.print(
                "+ This SCP appears safe to apply. No denials detected in historical data.",
                style="green",
            )
        elif risk_level == "LOW":
            self.console.print(
                "+ Low risk. Review denied actions above to ensure they are intentional.",
                style="green",
            )
            self.console.print(
                "  Consider testing in a non-production OU first.",
                style="dim",
            )
        elif risk_level == "MEDIUM":
            self.console.print(
                "WARNING: Medium risk detected. Carefully review all denied actions.",
                style="yellow",
            )
            self.console.print(
                "  Recommended: Test in a staging OU before production deployment.",
                style="yellow",
            )
        else:  # HIGH or CRITICAL
            self.console.print(
                "ALERT: High risk detected! This SCP would block significant activity.",
                style="red bold",
            )
            self.console.print(
                "  Action required:",
                style="red",
            )
            self.console.print(
                "  1. Review all denied actions and principals above",
                style="red",
            )
            self.console.print(
                "  2. Refine the SCP to reduce unintended denials",
                style="red",
            )
            self.console.print(
                "  3. Test in an isolated OU before broader deployment",
                style="red",
            )

        self.console.print()

    def print_quick_summary(self, summary: dict) -> None:
        """
        Print a quick summary from quick_summary() analysis.

        Args:
            summary: Dictionary from ImpactAnalyzer.quick_summary()
        """
        self.console.print("[bold cyan]Quick Analysis Summary[/bold cyan]")
        self.console.print("-" * 60)
        self.console.print(f"Sampled Events:  {summary['sampled_events']:,}")
        self.console.print(f"Denied:          {summary['denied_count']:,}")
        self.console.print(f"Allowed:         {summary['allowed_count']:,}")
        self.console.print(f"Denial Rate:     {summary['estimated_denial_rate']:.1f}%")

        if summary["is_sample"]:
            self.console.print(
                "\n[dim]Note: This is a sample. Run full analysis for complete results.[/dim]"
            )
        self.console.print()
