from __future__ import annotations

import time
from collections import defaultdict

from schemathesis.core.transport import Response
from schemathesis.engine.recorder import Interaction, ScenarioRecorder

from tracecov import HttpInteraction, HttpRequest, HttpResponse


def _transform_headers(headers: dict[str, list[str]]) -> dict[str, str]:
    return {key: value[0] for key, value in headers.items()}


def from_response(method: str, response: Response, timestamp: float | None = None) -> HttpInteraction:
    """Build an HttpInteraction from a schemathesis Response (e.g. from case.call())."""
    body = response.request.body
    if isinstance(body, str):
        body = body.encode("utf-8")
    return HttpInteraction(
        request=HttpRequest(
            method=method,
            url=response.request.url,
            body=body,
            headers=dict(response.request.headers),
        ),
        response=HttpResponse(
            status_code=response.status_code,
            elapsed=response.elapsed,
        ),
        timestamp=timestamp if timestamp is not None else time.time(),
    )


def to_http_interaction(method: str, interaction: Interaction) -> HttpInteraction:
    """Convert a schemathesis engine Interaction to a tracecov HttpInteraction."""
    return HttpInteraction(
        request=HttpRequest(
            method=method,
            url=interaction.request.uri,
            body=interaction.request.body,
            headers=_transform_headers(interaction.request.headers),
        ),
        response=HttpResponse(
            status_code=interaction.response.status_code,
            elapsed=interaction.response.elapsed,
        )
        if interaction.response
        else None,
        timestamp=interaction.timestamp,
    )


def group_interactions_by_method_path(recorder: ScenarioRecorder) -> dict[tuple[str, str], list[Interaction]]:
    """Group interactions by method and path template."""
    groups: dict[tuple[str, str], list[Interaction]] = defaultdict(list)

    for case_id, case_node in recorder.cases.items():
        case = case_node.value
        interaction = recorder.interactions.get(case_id)
        if interaction:
            groups[(case.method, case.operation.full_path)].append(interaction)
        else:
            # Could only happen with some hard-to-trigger network errors
            ...  # pragma: no cover

    return groups
