import html
import random
import re

import nh3
import pytest

from httpmessageprocessorutil.sanitizer import Nh3Sanitizer

pytestmark = pytest.mark.perf

_ENTITY_PATTERN = re.compile(r"&(?:[a-zA-Z][a-zA-Z0-9]*|#\d+|#[xX][0-9a-fA-F]+);|&")
_PLACEHOLDER_PATTERN = re.compile("\ue000(\\d+)\ue001")


def _baseline_sanitize(value):
    """Full pipeline with no fast paths — reference for benchmarking."""
    if not isinstance(value, str):
        return value

    entities = []

    def _store(match):
        entities.append(match.group(0))
        return f"\ue000{len(entities) - 1}\ue001"

    protected = _ENTITY_PATTERN.sub(_store, value)
    cleaned = nh3.clean(protected, tags=set())
    unescaped = html.unescape(cleaned)

    return _PLACEHOLDER_PATTERN.sub(
        lambda m: entities[int(m.group(1))],
        unescaped,
    )


PLAIN_SAMPLES = [
    "Acme Corporation",
    "Product description with no special characters",
    "John Doe",
    "Main Street 123",
    "SKU-12345",
    "Order #98765 completed successfully",
    "2026-04-16",
    "customer@example.com",
    "Brazil",
    "Premium Membership",
    "The quick brown fox jumps over the lazy dog",
    "Regular product name without markup",
    "Standard shipping option",
    "Credit card payment accepted",
    "Receipt printed",
    "Sao Paulo",
    "VISA 4xxx",
    "Cashback 5 percent",
    "Delivered on time",
    "In stock",
]

AMP_SAMPLES = [
    "AT&T Wireless Plan",
    "https://shop.example.com?id=1&ref=home&utm=abc",
    "Johnson & Johnson",
    "Procter & Gamble",
    "Fish & Chips",
    "5 &gt; 3 &amp; 2 &lt; 4",
    "Use &lt; and &gt; to wrap values",
]

BRACKET_SAMPLES = [
    "Price > $50",
    "Quantity < 10",
    "Use the -> operator",
    "Arrow <- direction",
    "foo > bar > baz",
]

XSS_SAMPLES = [
    '<script>alert("xss")</script>',
    "<img src=x onerror=alert(1)>",
    '"><button onclick=alert(1)>go</button>',
    "<b>bold</b>",
    '<a href="#">link</a> and more',
]


def _build_payload(n=10000, seed=42):
    rnd = random.Random(seed)
    result = []
    for _ in range(n):
        r = rnd.random()
        if r < 0.95:
            result.append(rnd.choice(PLAIN_SAMPLES))
        elif r < 0.98:
            result.append(rnd.choice(AMP_SAMPLES))
        elif r < 0.99:
            result.append(rnd.choice(BRACKET_SAMPLES))
        else:
            result.append(rnd.choice(XSS_SAMPLES))
    return result


PAYLOAD_SIZES = [1, 100, 1000]
PAYLOADS = {n: _build_payload(n) for n in PAYLOAD_SIZES}


def _build_huge_string(n_chars, seed=42):
    parts = _build_payload(n=max(n_chars // 20, 1), seed=seed)
    return " ".join(parts)[:n_chars]


HUGE_SIZES = [10_000, 100_000, 1_000_000]
HUGE_PAYLOADS = {n: _build_huge_string(n) for n in HUGE_SIZES}


@pytest.mark.parametrize("size", PAYLOAD_SIZES)
def test_benchmark_baseline(benchmark, size):
    payload = PAYLOADS[size]
    benchmark(lambda: [_baseline_sanitize(s) for s in payload])


@pytest.mark.parametrize("size", PAYLOAD_SIZES)
def test_benchmark_nh3Sanitizer(benchmark, size):
    sanitizer = Nh3Sanitizer()
    payload = PAYLOADS[size]
    benchmark(lambda: [sanitizer._sanitize(s) for s in payload])


@pytest.mark.parametrize("size", HUGE_SIZES)
def test_benchmark_hugeString_baseline(benchmark, size):
    payload = HUGE_PAYLOADS[size]
    benchmark(lambda: _baseline_sanitize(payload))


@pytest.mark.parametrize("size", HUGE_SIZES)
def test_benchmark_hugeString_nh3Sanitizer(benchmark, size):
    sanitizer = Nh3Sanitizer()
    payload = HUGE_PAYLOADS[size]
    benchmark(lambda: sanitizer._sanitize(payload))

