"""Suite 6 — Input reflection detection (XSS / header injection confirmation)."""

from __future__ import annotations
import asyncio
from typing import Any

import httpx

from .http_client import send_request
from .payloads import REFLECTION_MARKERS


async def run_reflection_tests(
    client: httpx.AsyncClient,
    url: str,
    method: str,
    headers: dict[str, str] | None,
    body: Any | None,
    mode: str = "full",
) -> list:
    from .runner import TestResult

    results: list[TestResult] = []
    base_body = body if isinstance(body, dict) else {}

    sem = asyncio.Semaphore(10)

    async def _probe(marker: str, location: str, inject_fn):
        async with sem:
            r = await inject_fn(marker)
            resp_body = r.get("body", "") or ""
            resp_headers_raw = str(r.get("headers", {}))
            reflected_body = marker in resp_body
            reflected_headers = marker in resp_headers_raw

            if reflected_body and "<" in marker:
                return TestResult(
                    test=f"Reflection [{location}]: {marker[:30]}",
                    status="CRASH",
                    detail="Input reflected in response body (HTML context — XSS likely)",
                    latency_ms=r["latency_ms"], category="reflection",
                    severity="CRITICAL", cwe="CWE-79",
                )
            if reflected_body:
                return TestResult(
                    test=f"Reflection [{location}]: {marker[:30]}",
                    status="WARN",
                    detail="Input reflected verbatim in response body",
                    latency_ms=r["latency_ms"], category="reflection",
                    severity="HIGH", cwe="CWE-79",
                )
            if reflected_headers:
                return TestResult(
                    test=f"Reflection [{location}]: {marker[:30]}",
                    status="WARN",
                    detail="Input reflected in response headers (header injection risk)",
                    latency_ms=r["latency_ms"], category="reflection",
                    severity="HIGH", cwe="CWE-113",
                )
            return TestResult(
                test=f"Reflection [{location}]: {marker[:30]}",
                status="PASS",
                detail="Not reflected",
                latency_ms=r["latency_ms"], category="reflection",
                severity="INFO", cwe="CWE-79",
            )

    tasks = []

    for marker_str, marker_desc in REFLECTION_MARKERS:
        # Inject into body fields
        async def _body_inject(m=marker_str):
            poisoned = {k: m for k in base_body} if base_body else {"input": m}
            return await send_request(client, url=url, method=method, headers=headers, body=poisoned)

        tasks.append(_probe(marker_str, "body", _body_inject))

        # Inject into URL query string
        async def _url_inject(m=marker_str):
            sep = "&" if "?" in url else "?"
            probe_url = f"{url}{sep}q={m}"
            return await send_request(client, url=probe_url, method="GET", headers=headers, body=None)

        tasks.append(_probe(marker_str, "query", _url_inject))

    # Inject into a custom header
    for marker_str, marker_desc in REFLECTION_MARKERS[:5]:
        async def _header_inject(m=marker_str):
            h = dict(headers or {})
            h["X-Custom-Input"] = m
            return await send_request(client, url=url, method=method, headers=h, body=body)

        tasks.append(_probe(marker_str, "header", _header_inject))

    # Inject into cookie
    for marker_str, marker_desc in REFLECTION_MARKERS[:3]:
        async def _cookie_inject(m=marker_str):
            h = dict(headers or {})
            h["Cookie"] = f"session={m}"
            return await send_request(client, url=url, method=method, headers=h, body=body)

        tasks.append(_probe(marker_str, "cookie", _cookie_inject))

    # Inject into Referer
    for marker_str, marker_desc in REFLECTION_MARKERS[:3]:
        async def _referer_inject(m=marker_str):
            h = dict(headers or {})
            h["Referer"] = f"https://evil.com/{m}"
            return await send_request(client, url=url, method=method, headers=h, body=body)

        tasks.append(_probe(marker_str, "referer", _referer_inject))

    # Inject into URL path
    for marker_str, marker_desc in REFLECTION_MARKERS[:3]:
        async def _path_inject(m=marker_str):
            probe_url = url.rstrip("/") + f"/{m}"
            return await send_request(client, url=probe_url, method="GET", headers=headers, body=None)

        tasks.append(_probe(marker_str, "path", _path_inject))

    results.extend(await asyncio.gather(*tasks))
    return results
