"""
CSRF Scanner - Main scanning orchestrator.

Coordinates input parsing, detection, and output generation.
"""

import json
from dataclasses import dataclass, field
from pathlib import Path
from typing import List, Optional
from datetime import datetime, timezone

from sentinel_csrf.input.cookies import Cookie, CookieParser
from sentinel_csrf.input.requests import HttpRequest, HttpRequestParser
from sentinel_csrf.core.detector import (
    CsrfDetector,
    DetectionResult,
    CsrfFinding,
    Severity,
    Confidence,
)


@dataclass
class ScanResult:
    """Result of a complete CSRF scan."""
    
    target: str
    timestamp: str
    requests_analyzed: int
    csrf_candidates: int
    confirmed_count: int
    likely_count: int
    informational_count: int
    suppressed_count: int
    
    findings: List[CsrfFinding] = field(default_factory=list)
    suppressed: List[dict] = field(default_factory=list)
    
    def to_dict(self) -> dict:
        """Convert to dictionary for JSON serialization."""
        return {
            "scan_metadata": {
                "tool": "sentinel-csrf",
                "version": "1.0.0",
                "timestamp": self.timestamp,
                "target": self.target,
            },
            "summary": {
                "requests_analyzed": self.requests_analyzed,
                "csrf_candidates": self.csrf_candidates,
                "confirmed": self.confirmed_count,
                "likely": self.likely_count,
                "informational": self.informational_count,
                "suppressed": self.suppressed_count,
            },
            "findings": [f.to_dict() for f in self.findings],
            "suppressed": self.suppressed,
        }
    
    def to_json(self, indent: int = 2) -> str:
        """Convert to JSON string."""
        return json.dumps(self.to_dict(), indent=indent)
    
    def to_markdown(self) -> str:
        """Generate markdown report."""
        lines = [
            "# Sentinel-CSRF Scan Report",
            "",
            f"**Target:** {self.target}",
            f"**Scan Time:** {self.timestamp}",
            "",
            "## Summary",
            "",
            f"| Metric | Count |",
            f"|--------|-------|",
            f"| Requests Analyzed | {self.requests_analyzed} |",
            f"| CSRF Candidates | {self.csrf_candidates} |",
            f"| Confirmed | {self.confirmed_count} |",
            f"| Likely | {self.likely_count} |",
            f"| Informational | {self.informational_count} |",
            f"| Suppressed | {self.suppressed_count} |",
            "",
        ]
        
        if self.findings:
            lines.extend([
                "## Findings",
                "",
            ])
            
            for finding in self.findings:
                severity_emoji = {
                    Severity.CRITICAL: "🔴",
                    Severity.HIGH: "🟠",
                    Severity.MEDIUM: "🟡",
                    Severity.LOW: "🟢",
                    Severity.INFO: "⚪",
                }.get(finding.severity, "⚪")
                
                lines.extend([
                    f"### {finding.id}: {finding.endpoint}",
                    "",
                    f"- **Severity:** {severity_emoji} {finding.severity.value.upper()}",
                    f"- **Confidence:** {finding.confidence.value}",
                    f"- **Type:** {finding.csrf_type.value}",
                    f"- **Method:** {finding.method}",
                    f"- **Attack Vector:** {finding.attack_vector.value if finding.attack_vector else 'N/A'}",
                    "",
                    "**Reasons:**",
                    "",
                ])
                
                for reason in finding.reasons:
                    lines.append(f"- {reason}")
                
                lines.extend([
                    "",
                    f"**Recommendation:** {finding.recommendation}",
                    "",
                    "---",
                    "",
                ])
        else:
            lines.extend([
                "## Findings",
                "",
                "No CSRF vulnerabilities detected.",
                "",
            ])
        
        if self.suppressed:
            lines.extend([
                "## Suppressed (Not Exploitable)",
                "",
            ])
            for item in self.suppressed[:10]:  # Limit to 10
                lines.append(f"- `{item.get('endpoint', 'unknown')}`: {item.get('reason', 'N/A')}")
            
            if len(self.suppressed) > 10:
                lines.append(f"- ... and {len(self.suppressed) - 10} more")
            lines.append("")
        
        lines.extend([
            "---",
            "",
            "*Generated by Sentinel-CSRF v1.0.0*",
        ])
        
        return "\n".join(lines)


class CsrfScanner:
    """
    Main CSRF scanning orchestrator.
    
    Coordinates:
    - Cookie loading
    - Request parsing
    - Detection pipeline
    - Result aggregation
    """
    
    @classmethod
    def scan(
        cls,
        cookie_file: Path,
        request_file: Path,
        suppress_informational: bool = False,
    ) -> ScanResult:
        """
        Perform a CSRF scan.
        
        Args:
            cookie_file: Path to Netscape cookie file
            request_file: Path to raw HTTP request file
            suppress_informational: Hide low-confidence findings
        
        Returns:
            ScanResult with all findings and statistics
        """
        # Load cookies
        cookies = CookieParser.parse_netscape_file(cookie_file)
        
        # Parse request(s)
        content = request_file.read_text()
        if "---" in content:
            requests = HttpRequestParser.parse_multiple(content)
        else:
            requests = [HttpRequestParser.parse(content)]
        
        # Extract target from first request
        target = requests[0].host if requests else "unknown"
        
        # Run detection on each request
        findings: List[CsrfFinding] = []
        suppressed: List[dict] = []
        
        for request in requests:
            result = CsrfDetector.detect(request, cookies)
            
            if result.is_vulnerable and result.finding:
                # Filter informational if requested
                if suppress_informational and result.finding.confidence == Confidence.INFORMATIONAL:
                    suppressed.append({
                        "endpoint": request.path,
                        "reason": "Informational finding suppressed",
                    })
                else:
                    findings.append(result.finding)
            elif result.suppression_reason:
                suppressed.append({
                    "endpoint": request.path,
                    "reason": result.suppression_reason,
                })
        
        # Count by confidence
        confirmed = sum(1 for f in findings if f.confidence == Confidence.CONFIRMED)
        likely = sum(1 for f in findings if f.confidence == Confidence.LIKELY)
        informational = sum(1 for f in findings if f.confidence == Confidence.INFORMATIONAL)
        
        return ScanResult(
            target=target,
            timestamp=datetime.now(timezone.utc).isoformat(),
            requests_analyzed=len(requests),
            csrf_candidates=len(findings) + len([s for s in suppressed if "not state-changing" not in s.get("reason", "").lower()]),
            confirmed_count=confirmed,
            likely_count=likely,
            informational_count=informational,
            suppressed_count=len(suppressed),
            findings=findings,
            suppressed=suppressed,
        )
    
    @classmethod
    def scan_single_request(
        cls,
        request: HttpRequest,
        cookies: Optional[List[Cookie]] = None,
    ) -> DetectionResult:
        """
        Scan a single request (for programmatic use).
        """
        return CsrfDetector.detect(request, cookies)


def scan_for_csrf(
    cookie_file: Path,
    request_file: Path,
    suppress_informational: bool = False,
) -> ScanResult:
    """
    Convenience function to perform a CSRF scan.
    
    This is the main entry point for scanning.
    """
    return CsrfScanner.scan(cookie_file, request_file, suppress_informational)
