"""Diff command for comparing scan results."""

import json
from pathlib import Path
from typing import Annotated

import typer
from apiposture.core.models.scan_result import ScanResult
from rich.console import Console
from rich.table import Table

from apiposture_pro.features.diff_mode.analyzer import DiffAnalyzer
from apiposture_pro.licensing.manager import ProLicenseManager

app = typer.Typer(help="Diff commands")
console = Console()


@app.command("diff")
def diff(
    baseline: Annotated[
        Path,
        typer.Argument(
            help="Baseline scan result file (JSON)",
            exists=True,
            file_okay=True,
            dir_okay=False,
        ),
    ],
    current: Annotated[
        Path,
        typer.Argument(
            help="Current scan result file (JSON)",
            exists=True,
            file_okay=True,
            dir_okay=False,
        ),
    ],
    summary_only: Annotated[
        bool,
        typer.Option(
            "--summary-only",
            help="Show only summary, not detailed changes",
        ),
    ] = False,
    fail_on_regression: Annotated[
        bool,
        typer.Option(
            "--fail-on-regression/--no-fail-on-regression",
            help="Exit with code 1 if regressions detected",
        ),
    ] = True,
) -> None:
    """
    Compare two scan results and show differences.

    Requires valid Pro license.
    """
    # Validate license
    license_manager = ProLicenseManager()
    if not license_manager.is_valid():
        console.print("[red]✗[/red] No valid license found")
        console.print("\nActivate your license with: apiposture-pro activate <key>")
        raise typer.Exit(1)

    try:
        # Load scan results
        console.print(f"[dim]Loading baseline: {baseline}[/dim]")
        baseline_result = _load_scan_result(baseline)

        console.print(f"[dim]Loading current: {current}[/dim]")
        current_result = _load_scan_result(current)

        # Perform diff
        console.print("[dim]Comparing results...[/dim]\n")
        analyzer = DiffAnalyzer()
        diff_result = analyzer.compare(baseline_result, current_result)

        # Display results
        _display_diff_result(diff_result, summary_only)

        # Exit with error if regressions detected
        if fail_on_regression and diff_result.has_regressions:
            console.print(
                f"\n[red]✗[/red] Detected {diff_result.regression_count} regression(s)"
            )
            raise typer.Exit(1)

    except Exception as e:
        console.print(f"\n[red]✗[/red] Diff failed: {e}")
        raise typer.Exit(1) from e


def _load_scan_result(file_path: Path) -> ScanResult:
    """Load scan result from JSON file."""
    with open(file_path) as f:
        data = json.load(f)

    # Reconstruct ScanResult from JSON
    # This is a simplified version - in production would use proper serialization
    from pathlib import Path as PathType

    from apiposture.core.models.endpoint import Endpoint
    from apiposture.core.models.enums import EndpointType, Framework, HttpMethod, Severity
    from apiposture.core.models.finding import Finding

    endpoints = []
    for ep_data in data.get("endpoints", []):
        # Convert method string to HttpMethod enum
        methods = [HttpMethod[m.upper()] if isinstance(m, str) else m for m in ep_data.get("methods", ["GET"])]
        if "method" in ep_data:  # Handle old format
            methods = [HttpMethod[ep_data["method"].upper()]]

        endpoints.append(
            Endpoint(
                route=ep_data.get("path", ep_data.get("route", "/")),
                methods=methods,
                file_path=PathType(ep_data.get("file_path", "unknown.py")),
                line_number=ep_data.get("line_number", 0),
                framework=Framework.FASTAPI,
                endpoint_type=EndpointType.ROUTER,
                function_name=ep_data.get("function_name", "unknown"),
            )
        )

    findings = []
    for f_data in data.get("findings", []):
        # Create a minimal endpoint for the finding
        endpoint = Endpoint(
            route="/",
            methods=[HttpMethod.GET],
            file_path=PathType(f_data.get("file_path", "unknown.py")),
            line_number=f_data.get("line_number", 0),
            framework=Framework.FASTAPI,
            endpoint_type=EndpointType.ROUTER,
            function_name="unknown",
        )

        findings.append(
            Finding(
                rule_id=f_data.get("rule_id", ""),
                rule_name=f_data.get("title", f_data.get("rule_name", "")),
                severity=Severity[f_data.get("severity", "INFO").upper()],
                message=f_data.get("description", f_data.get("message", "")),
                endpoint=endpoint,
                recommendation=f_data.get("recommendation", ""),
            )
        )

    return ScanResult(
        scan_path=PathType(data.get("project_path", data.get("scan_path", "/"))),
        endpoints=endpoints,
        findings=findings,
    )


def _display_diff_result(diff_result, summary_only: bool) -> None:
    """Display diff result to console."""
    # Show summary
    console.print("[bold]Diff Summary[/bold]\n")
    console.print(diff_result.summary)

    if summary_only:
        return

    # Show detailed changes
    if diff_result.new_findings:
        console.print("\n[bold red]New Findings:[/bold red]")
        _display_findings_table(diff_result.new_findings)

    if diff_result.resolved_findings:
        console.print("\n[bold green]Resolved Findings:[/bold green]")
        _display_findings_table(diff_result.resolved_findings)

    if diff_result.new_endpoints:
        console.print("\n[bold cyan]New Endpoints:[/bold cyan]")
        for endpoint in diff_result.new_endpoints:
            console.print(f"  + {endpoint}")

    if diff_result.removed_endpoints:
        console.print("\n[bold yellow]Removed Endpoints:[/bold yellow]")
        for endpoint in diff_result.removed_endpoints:
            console.print(f"  - {endpoint}")


def _display_findings_table(findings) -> None:
    """Display findings in a table."""
    table = Table(show_header=True)
    table.add_column("Severity", style="cyan")
    table.add_column("Rule ID", style="magenta")
    table.add_column("Title")
    table.add_column("Location", style="dim")

    for finding in findings[:10]:  # Limit to first 10
        severity_value = finding.severity.value if hasattr(finding.severity, "value") else str(finding.severity)
        severity_color = {
            "critical": "red",
            "high": "red",
            "medium": "yellow",
            "low": "blue",
            "info": "dim",
        }.get(severity_value.lower(), "white")

        # Get file path from endpoint
        file_path = "unknown"
        line_number = 0
        if hasattr(finding, "endpoint") and finding.endpoint:
            file_path = str(finding.endpoint.file_path)
            line_number = finding.endpoint.line_number

        table.add_row(
            f"[{severity_color}]{severity_value.upper()}[/{severity_color}]",
            finding.rule_id,
            finding.rule_name,
            f"{file_path}:{line_number}",
        )

    console.print(table)

    if len(findings) > 10:
        console.print(f"[dim]  ... and {len(findings) - 10} more[/dim]")
