"""Step definitions for HTTPS enforcement tests."""

from __future__ import annotations

import httpx
import pytest
from pytest_bdd import given, parsers, scenarios, then, when

# ---------------------------------------------------------------------------
# Scenarios
# ---------------------------------------------------------------------------

scenarios("test_https.feature")


# ---------------------------------------------------------------------------
# Steps - HTTPS enforcement
# ---------------------------------------------------------------------------


@given(parsers.parse("{product} is configured with an HTTPS URL"), target_fixture="product_url")
def product_configured_https(product, vip_config):
    product_key = product.lower().replace(" ", "_")
    pc = vip_config.product_config(product_key)
    if not pc.is_configured:
        pytest.skip(f"{product} is not configured")
    assert pc.url.startswith("https://"), f"{product} URL is not HTTPS: {pc.url}"
    return pc.url


@when(parsers.parse("I make an HTTP request to {product}"), target_fixture="http_result")
def make_http_request(product_url):
    http_url = product_url.replace("https://", "http://")
    try:
        resp = httpx.get(http_url, follow_redirects=False, timeout=10)
        return {
            "status": resp.status_code,
            "location": resp.headers.get("location", ""),
            "refused": False,
        }
    except httpx.ConnectError:
        return {"status": None, "location": "", "refused": True}
    except Exception:
        return {"status": None, "location": "", "refused": True}


@then("the connection is refused or redirected to HTTPS")
def https_enforced(http_result):
    if http_result["refused"]:
        return  # HTTP port closed - good.
    status = http_result["status"]
    assert status in (301, 302, 307, 308), (
        f"HTTP request was not refused or redirected (got HTTP {status}). HTTPS is not enforced."
    )
    assert http_result["location"].startswith("https://"), (
        f"Redirect does not point to HTTPS: {http_result['location']}"
    )


# ---------------------------------------------------------------------------
# Steps - header exposure
# ---------------------------------------------------------------------------


@when(parsers.parse("I inspect response headers from {product}"), target_fixture="response_headers")
def inspect_headers(product, vip_config):
    product_key = product.lower().replace(" ", "_")
    pc = vip_config.product_config(product_key)
    if not pc.is_configured:
        pytest.skip(f"{product} is not configured")
    resp = httpx.get(pc.url, follow_redirects=True, timeout=15)
    return dict(resp.headers)


@then("the server does not expose version information in headers")
def no_version_headers(response_headers):
    # Check for common headers that leak server version info.
    risky_headers = ["x-powered-by", "server"]
    for header in risky_headers:
        value = response_headers.get(header, "")
        # Having the header is OK, but it shouldn't contain version numbers.
        if value:
            import re

            version_pattern = re.compile(r"\d+\.\d+")
            if version_pattern.search(value):
                pytest.fail(
                    f"Header '{header}: {value}' exposes version info. "
                    "Configure the server to suppress version details."
                )
