"""Scan tools — wraps AgentScanner for the pentesting agent.

Provides ``run_scan`` and ``run_phase`` tools that let the pentesting
agent execute full campaigns or individual phases against a target.
"""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING, Any

if TYPE_CHECKING:
    from collections.abc import Callable

    from ziran.application.agent_scanner.scanner import AgentScanner, ProgressEvent
    from ziran.domain.entities.phase import ScanPhase

logger = logging.getLogger(__name__)


async def run_scan(
    scanner: AgentScanner,
    *,
    phases: list[str] | None = None,
    coverage: str = "standard",
    concurrency: int = 5,
    stop_on_critical: bool = True,
    streaming: bool = False,
    on_progress: Callable[[ProgressEvent], None] | None = None,
    exclude_vectors: set[str] | None = None,
) -> dict[str, Any]:
    """Run a full scan campaign against the target agent.

    Args:
        scanner: The pre-configured AgentScanner instance.
        phases: Phase names to run (default: core phases).
        coverage: Coverage level: 'essential', 'standard', or 'comprehensive'.
        concurrency: Max concurrent attacks per phase.
        stop_on_critical: Stop on critical finding.
        streaming: Use streaming invocation.
        on_progress: Callback for scan-level progress events.
        exclude_vectors: Vector IDs to skip (already tested).

    Returns:
        Structured campaign result summary.
    """
    from ziran.application.strategies.fixed import FixedStrategy
    from ziran.domain.entities.phase import CoverageLevel, ScanPhase

    phase_list: list[ScanPhase] | None = None
    if phases:
        phase_list = [ScanPhase(p) for p in phases]

    strategy = FixedStrategy(stop_on_critical=stop_on_critical)
    coverage_level = CoverageLevel(coverage.lower())

    result = await scanner.run_campaign(
        phases=phase_list,
        stop_on_critical=stop_on_critical,
        coverage=coverage_level,
        max_concurrent_attacks=concurrency,
        strategy=strategy,
        streaming=streaming,
        on_progress=on_progress,
        exclude_vectors=exclude_vectors,
    )

    successful_attacks = [r for r in result.attack_results if r.get("successful")]
    return {
        "campaign_id": result.campaign_id,
        "phases_executed": len(result.phases_executed),
        "total_vulnerabilities": result.total_vulnerabilities,
        "final_trust_score": result.final_trust_score,
        "critical_paths": result.critical_paths[:5],
        "successful_attacks": [
            {
                "vector_id": a.get("vector_id", ""),
                "vector_name": a.get("vector_name", ""),
                "category": a.get("category", ""),
                "severity": a.get("severity", ""),
            }
            for a in successful_attacks[:20]
        ],
        "total_attacks_executed": len(result.attack_results),
        "token_usage": result.token_usage,
    }


async def run_phase(
    scanner: AgentScanner,
    *,
    phase: str,
    coverage: str = "standard",
    concurrency: int = 5,
    on_progress: Callable[[ProgressEvent], None] | None = None,
    exclude_vectors: set[str] | None = None,
) -> dict[str, Any]:
    """Run a single scan phase against the target agent.

    Args:
        scanner: The pre-configured AgentScanner instance.
        phase: Phase name to run.
        coverage: Coverage level.
        concurrency: Max concurrent attacks.
        on_progress: Callback for scan-level progress events.
        exclude_vectors: Vector IDs to skip (already tested).

    Returns:
        Structured phase result summary.
    """
    from ziran.domain.entities.phase import CoverageLevel, ScanPhase

    scan_phase = ScanPhase(phase)
    coverage_level = CoverageLevel(coverage.lower())

    result = await scanner.run_campaign(
        phases=[scan_phase],
        stop_on_critical=False,
        coverage=coverage_level,
        max_concurrent_attacks=concurrency,
        on_progress=on_progress,
        exclude_vectors=exclude_vectors,
    )

    phase_result = result.phases_executed[0] if result.phases_executed else None
    return {
        "phase": phase,
        "vulnerabilities_found": phase_result.vulnerabilities_found if phase_result else [],
        "trust_score": phase_result.trust_score if phase_result else 0.0,
        "duration_seconds": phase_result.duration_seconds if phase_result else 0.0,
        "attacks_executed": len(result.attack_results),
        "successful_attacks": [
            {
                "vector_id": a.get("vector_id", ""),
                "vector_name": a.get("vector_name", ""),
                "category": a.get("category", ""),
                "severity": a.get("severity", ""),
            }
            for a in result.attack_results
            if a.get("successful")
        ],
        "token_usage": phase_result.token_usage if phase_result else {},
    }
