#!/usr/bin/env python3
"""
souleyez.ui.wazuh_vulns_view - Wazuh Vulnerabilities View

Displays vulnerabilities discovered by Wazuh agents with sync,
filtering, and status management capabilities.
"""
import click
from rich.console import Console
from rich.table import Table
from rich.panel import Panel
from rich.text import Text
from typing import List, Dict, Optional
from souleyez.storage.wazuh_vulns import WazuhVulnsManager
from souleyez.integrations.wazuh import WazuhVulnSync, WazuhConfig, WazuhHostMapper

console = Console()

# Severity colors
SEVERITY_COLORS = {
    'Critical': 'red bold',
    'High': 'yellow',
    'Medium': 'white',
    'Low': 'dim'
}

# Status icons
STATUS_ICONS = {
    'open': '🔴',
    'confirmed': '✅',
    'exploited': '💥',
    'false_positive': '⚪'
}


def show_wazuh_vulns_view(engagement_id: int, engagement_name: str = "") -> None:
    """
    Display Wazuh vulnerabilities view.

    Args:
        engagement_id: Current engagement ID
        engagement_name: Engagement name for display
    """
    vulns_manager = WazuhVulnsManager()
    host_mapper = WazuhHostMapper()

    while True:
        console.clear()
        width = console.size.width

        # Header
        console.print(Panel("Wazuh Vulnerabilities", style="bold cyan", width=min(width - 4, 60)))

        # Check if Wazuh is configured
        config = WazuhConfig.get_config(engagement_id)
        if not config or not config.get('enabled'):
            console.print(Panel(
                "[yellow]Wazuh is not configured for this engagement.[/yellow]\n\n"
                "Configure Wazuh in Settings → Integrations → Wazuh SIEM",
                title="Not Configured",
                border_style="yellow"
            ))
            console.print("\n[dim]Press any key to return...[/dim]")
            click.getchar()
            return

        # Get sync status
        sync = WazuhVulnSync(engagement_id)
        sync_status = sync.get_sync_status()

        # Get summary
        summary = vulns_manager.get_summary(engagement_id)
        mapping_stats = host_mapper.get_mapping_stats(engagement_id)

        # Sync status panel
        if sync_status.get('synced'):
            last_sync = sync_status.get('last_sync_at', 'Unknown')
            stale_indicator = " [yellow](stale)[/yellow]" if sync_status.get('is_stale') else " [green](fresh)[/green]"
            sync_info = f"Last sync: {last_sync}{stale_indicator} | Count: {sync_status.get('last_sync_count', 0)}"
        else:
            sync_info = "[yellow]Never synced - press [s] to sync now[/yellow]"

        console.print(Panel(sync_info, title="Sync Status", border_style="blue"))

        # Summary stats
        _render_summary(summary, mapping_stats, width)

        # Get vulnerabilities
        vulns = vulns_manager.list_vulnerabilities(engagement_id, limit=50)

        if vulns:
            _render_vulns_table(vulns, width)
        else:
            console.print("\n[dim]No vulnerabilities synced yet. Press [s] to sync from Wazuh.[/dim]")

        # Menu
        console.print("\n" + "─" * width)
        console.print(
            "[cyan][s][/cyan] Sync Now  "
            "[cyan][f][/cyan] Filter  "
            "[cyan][m][/cyan] Map Hosts  "
            "[cyan][d][/cyan] Details  "
            "[cyan][q][/cyan] Back"
        )

        key = click.getchar().lower()

        if key == 'q':
            return
        elif key == 's':
            _do_sync(engagement_id)
        elif key == 'f':
            _filter_menu(engagement_id, engagement_name)
        elif key == 'm':
            _mapping_menu(engagement_id)
        elif key == 'd':
            _detail_view(engagement_id, vulns)


def _render_summary(summary: Dict, mapping_stats: Dict, width: int) -> None:
    """Render summary statistics."""
    total = summary.get('total', 0)
    verified = summary.get('verified', 0)
    by_sev = summary.get('by_severity', {})

    mapped = mapping_stats.get('mapped', 0)
    unmapped = mapping_stats.get('unmapped', 0)

    # Build summary text
    sev_parts = []
    for sev in ['Critical', 'High', 'Medium', 'Low']:
        count = by_sev.get(sev, 0)
        if count > 0:
            color = SEVERITY_COLORS.get(sev, 'white')
            sev_parts.append(f"[{color}]{sev}: {count}[/{color}]")

    sev_text = " | ".join(sev_parts) if sev_parts else "No vulnerabilities"

    summary_text = (
        f"Total: [bold]{total}[/bold] | Verified: [green]{verified}[/green] | "
        f"Mapped: {mapped} | Unmapped: [yellow]{unmapped}[/yellow]\n"
        f"{sev_text}"
    )

    console.print(Panel(summary_text, title="Summary", border_style="cyan"))


def _render_vulns_table(vulns: List[Dict], width: int) -> None:
    """Render vulnerabilities table."""
    table = Table(
        show_header=True,
        header_style="bold cyan",
        box=None,
        padding=(0, 1),
        width=min(width - 4, 140)
    )

    table.add_column("#", width=3, style="dim")
    table.add_column("CVE", width=18)
    table.add_column("SEV", width=10)
    table.add_column("HOST", width=15)
    table.add_column("PACKAGE", width=25)
    table.add_column("VERSION", width=15)
    table.add_column("STATUS", width=8)
    table.add_column("CVSS", width=5)

    for idx, vuln in enumerate(vulns, 1):
        cve = vuln.get('cve_id', '-')
        severity = vuln.get('severity', 'Medium')
        host_ip = vuln.get('host_ip') or vuln.get('agent_ip', '-')
        package = vuln.get('package_name', '-')[:24]
        version = vuln.get('package_version', '-')[:14]
        status = vuln.get('status', 'open')
        cvss = vuln.get('cvss_score')

        # Format severity
        sev_color = SEVERITY_COLORS.get(severity, 'white')
        sev_display = f"[{sev_color}]{severity}[/{sev_color}]"

        # Format status
        status_icon = STATUS_ICONS.get(status, '🔴')

        # Format CVSS
        cvss_display = f"{cvss:.1f}" if cvss else "-"

        table.add_row(
            str(idx),
            cve,
            sev_display,
            host_ip,
            package,
            version,
            status_icon,
            cvss_display
        )

    console.print(table)

    if len(vulns) >= 50:
        console.print("[dim]Showing first 50 results. Use filters to narrow down.[/dim]")


def _do_sync(engagement_id: int) -> None:
    """Perform sync from Wazuh."""
    console.clear()
    console.print(Panel("Syncing vulnerabilities from Wazuh...", border_style="blue"))

    sync = WazuhVulnSync(engagement_id)

    with console.status("[bold blue]Fetching vulnerabilities..."):
        result = sync.sync_full()

    console.print()

    if result.success:
        console.print(f"[green]✓ Sync complete![/green]")
        console.print(f"  Fetched: {result.total_fetched}")
        console.print(f"  New: {result.new_vulns}")
        console.print(f"  Updated: {result.updated_vulns}")
        console.print(f"  Mapped hosts: {result.mapped_hosts}")

        if result.unmapped_agents:
            console.print(f"\n[yellow]Unmapped agents ({len(result.unmapped_agents)}):[/yellow]")
            for agent_ip in result.unmapped_agents[:5]:
                console.print(f"  - {agent_ip}")
            if len(result.unmapped_agents) > 5:
                console.print(f"  ... and {len(result.unmapped_agents) - 5} more")

        if result.errors:
            console.print(f"\n[yellow]Errors ({len(result.errors)}):[/yellow]")
            for err in result.errors[:3]:
                console.print(f"  - {err}")
    else:
        console.print(f"[red]✗ Sync failed[/red]")
        for err in result.errors:
            console.print(f"  [red]{err}[/red]")

    console.print(f"\n[dim]Duration: {result.duration_seconds:.1f}s[/dim]")
    console.print("\n[dim]Press any key to continue...[/dim]")
    click.getchar()


def _filter_menu(engagement_id: int, engagement_name: str) -> None:
    """Show filter options."""
    vulns_manager = WazuhVulnsManager()

    while True:
        console.clear()
        console.print(Panel("Filter Vulnerabilities", border_style="cyan"))

        console.print("[1] By Severity")
        console.print("[2] By Host/Agent")
        console.print("[3] By CVE ID")
        console.print("[4] By Status")
        console.print("[5] Show All (clear filters)")
        console.print("[q] Back")

        key = click.getchar().lower()

        if key == 'q':
            return
        elif key == '1':
            _filter_by_severity(engagement_id)
        elif key == '2':
            _filter_by_host(engagement_id)
        elif key == '3':
            _filter_by_cve(engagement_id)
        elif key == '4':
            _filter_by_status(engagement_id)
        elif key == '5':
            vulns = vulns_manager.list_vulnerabilities(engagement_id)
            _show_filtered_results(vulns, "All Vulnerabilities")


def _filter_by_severity(engagement_id: int) -> None:
    """Filter by severity."""
    console.print("\nSelect severity:")
    console.print("[1] Critical  [2] High  [3] Medium  [4] Low")

    key = click.getchar()
    severity_map = {'1': 'Critical', '2': 'High', '3': 'Medium', '4': 'Low'}
    severity = severity_map.get(key)

    if severity:
        vulns_manager = WazuhVulnsManager()
        vulns = vulns_manager.list_vulnerabilities(engagement_id, severity=severity)
        _show_filtered_results(vulns, f"Severity: {severity}")


def _filter_by_host(engagement_id: int) -> None:
    """Filter by host/agent IP."""
    console.print("\nEnter IP address (partial match): ", end="")
    ip = input().strip()

    if ip:
        vulns_manager = WazuhVulnsManager()
        vulns = vulns_manager.list_vulnerabilities(engagement_id, agent_ip=ip)
        _show_filtered_results(vulns, f"Host: {ip}")


def _filter_by_cve(engagement_id: int) -> None:
    """Filter by CVE ID."""
    console.print("\nEnter CVE ID (partial match): ", end="")
    cve = input().strip()

    if cve:
        vulns_manager = WazuhVulnsManager()
        vulns = vulns_manager.list_vulnerabilities(engagement_id, cve_id=cve)
        _show_filtered_results(vulns, f"CVE: {cve}")


def _filter_by_status(engagement_id: int) -> None:
    """Filter by status."""
    console.print("\nSelect status:")
    console.print("[1] Open  [2] Confirmed  [3] Exploited  [4] False Positive")

    key = click.getchar()
    status_map = {'1': 'open', '2': 'confirmed', '3': 'exploited', '4': 'false_positive'}
    status = status_map.get(key)

    if status:
        vulns_manager = WazuhVulnsManager()
        vulns = vulns_manager.list_vulnerabilities(engagement_id, status=status)
        _show_filtered_results(vulns, f"Status: {status}")


def _show_filtered_results(vulns: List[Dict], filter_name: str) -> None:
    """Show filtered results."""
    console.clear()
    width = console.size.width

    console.print(Panel(f"Filtered by: {filter_name} | Results: {len(vulns)}", border_style="cyan"))

    if vulns:
        _render_vulns_table(vulns, width)
    else:
        console.print("[dim]No vulnerabilities match the filter.[/dim]")

    console.print("\n[dim]Press any key to continue...[/dim]")
    click.getchar()


def _mapping_menu(engagement_id: int) -> None:
    """Show host mapping options."""
    host_mapper = WazuhHostMapper()

    console.clear()
    console.print(Panel("Host Mapping", border_style="cyan"))

    # Get mapping stats
    stats = host_mapper.get_mapping_stats(engagement_id)
    console.print(f"Mapped: {stats['mapped']} | Unmapped: {stats['unmapped']} | Total: {stats['total']}")

    # Show unmapped agents
    unmapped = host_mapper.get_unmapped_agents(engagement_id)
    if unmapped:
        console.print("\n[yellow]Unmapped Agents:[/yellow]")
        for agent in unmapped[:10]:
            console.print(f"  - {agent.get('agent_ip')} ({agent.get('agent_name', 'unknown')}) - {agent.get('vuln_count')} vulns")

        # Show suggestions
        suggestions = host_mapper.suggest_mappings(engagement_id)
        if suggestions:
            console.print("\n[cyan]Suggested Mappings:[/cyan]")
            for sug in suggestions[:5]:
                console.print(
                    f"  {sug['agent_ip']} → {sug['suggested_host_ip']} "
                    f"({sug.get('suggested_host_name', '-')}) - {sug['reason']}"
                )
    else:
        console.print("\n[green]All agents are mapped to hosts.[/green]")

    console.print("\n[1] Auto-map all  [2] Manual map  [q] Back")

    key = click.getchar().lower()

    if key == '1':
        with console.status("[bold blue]Auto-mapping agents to hosts..."):
            mapping = host_mapper.auto_map_all(engagement_id)

        mapped_count = sum(1 for h in mapping.values() if h)
        console.print(f"\n[green]✓ Mapped {mapped_count} agents to hosts[/green]")
        console.print("\n[dim]Press any key to continue...[/dim]")
        click.getchar()


def _detail_view(engagement_id: int, vulns: List[Dict]) -> None:
    """Show detailed view of a vulnerability."""
    if not vulns:
        return

    console.print("\nEnter vulnerability # to view details: ", end="")
    try:
        idx = int(input().strip()) - 1
        if 0 <= idx < len(vulns):
            vuln = vulns[idx]
            _show_vuln_detail(vuln)
    except (ValueError, IndexError):
        pass


def _show_vuln_detail(vuln: Dict) -> None:
    """Show detailed vulnerability info."""
    console.clear()

    cve = vuln.get('cve_id', 'Unknown')
    severity = vuln.get('severity', 'Medium')
    sev_color = SEVERITY_COLORS.get(severity, 'white')

    console.print(Panel(
        f"[bold]{cve}[/bold]\n"
        f"[{sev_color}]{severity}[/{sev_color}] | CVSS: {vuln.get('cvss_score', '-')}",
        title="Vulnerability Details",
        border_style="cyan"
    ))

    # Info sections
    console.print("\n[bold]Agent/Host:[/bold]")
    console.print(f"  Agent ID: {vuln.get('agent_id', '-')}")
    console.print(f"  Agent Name: {vuln.get('agent_name', '-')}")
    console.print(f"  Agent IP: {vuln.get('agent_ip', '-')}")
    console.print(f"  Mapped Host: {vuln.get('host_ip', 'Not mapped')}")

    console.print("\n[bold]Package:[/bold]")
    console.print(f"  Name: {vuln.get('package_name', '-')}")
    console.print(f"  Version: {vuln.get('package_version', '-')}")
    console.print(f"  Architecture: {vuln.get('package_architecture', '-')}")

    console.print("\n[bold]Detection:[/bold]")
    console.print(f"  Detected: {vuln.get('detection_time', '-')}")
    console.print(f"  Published: {vuln.get('published_date', '-')}")
    console.print(f"  Status: {vuln.get('status', 'open')}")
    console.print(f"  Verified by scan: {'Yes' if vuln.get('verified_by_scan') else 'No'}")

    # References
    refs = vuln.get('reference_urls', [])
    if refs:
        console.print("\n[bold]References:[/bold]")
        for ref in refs[:5]:
            console.print(f"  - {ref}")

    console.print("\n[dim]Press any key to return...[/dim]")
    click.getchar()
