"""Convert captured HTTP traffic into a VenomQA Journey skeleton."""

from __future__ import annotations

import json
import re
from typing import Any

from venomqa.v1.recording.recorder import RecordedRequest

# ---------------------------------------------------------------------------
# Public API
# ---------------------------------------------------------------------------


def generate_journey_code(
    captured: list[RecordedRequest],
    journey_name: str = "recorded_journey",
    base_url: str = "",
) -> str:
    """Convert a list of RecordedRequests into runnable VenomQA Python code.

    The generated code is a valid Python module that can be fed directly to
    ``venomqa explore <file> --base-url ...``.

    Args:
        captured: The captured HTTP traffic (from ``RequestRecorder.captured``).
        journey_name: Name to give the Journey (default: "recorded_journey").
        base_url: The base URL used during recording (for documentation only).

    Returns:
        A Python source string.
    """
    if not captured:
        return _empty_journey(journey_name)

    action_blocks: list[str] = []
    step_names: list[str] = []

    for i, req in enumerate(captured):
        action_name = _make_action_name(req, i)
        step_names.append(action_name)
        action_blocks.append(_render_action(action_name, req))

    steps_list = ",\n    ".join(f'Step("{name}", {name})' for name in step_names)

    header = _file_header(journey_name, base_url, len(captured))
    actions_code = "\n\n".join(action_blocks)

    return f"""{header}

{actions_code}


# ---------------------------------------------------------------------------
# Journey
# ---------------------------------------------------------------------------

journey = Journey(
    name="{journey_name}",
    steps=[
    {steps_list},
    ],
)
"""


# ---------------------------------------------------------------------------
# Internal helpers
# ---------------------------------------------------------------------------


def _file_header(journey_name: str, base_url: str, count: int) -> str:
    return f'''"""Auto-generated VenomQA journey — {count} recorded request(s).

Source URL: {base_url or "(unknown)"}
Journey:    {journey_name}

This file was generated by ``venomqa record``.  Edit freely.
"""

from venomqa.v1 import Journey, Step, Action, ActionResult, HTTPRequest, HTTPResponse'''


def _empty_journey(name: str) -> str:
    return f'''"""Auto-generated VenomQA journey — no requests recorded."""

from venomqa.v1 import Journey, Step

journey = Journey(name="{name}", steps=[])
'''


def _make_action_name(req: RecordedRequest, index: int) -> str:
    """Derive a Python-safe function name from a request."""
    method = req.method.lower()
    # Strip scheme+host, keep only the path segment
    url = req.url
    if "://" in url:
        # e.g. https://api.github.com/repos/owner/repo → /repos/owner/repo
        url = "/" + url.split("/", 3)[-1] if url.count("/") >= 3 else "/"
    path = url.split("?")[0].lstrip("/")
    # Collapse path segments, replace non-alphanum with _
    clean = re.sub(r"[^a-z0-9]", "_", path.lower())
    clean = re.sub(r"_+", "_", clean).strip("_")
    # Truncate long names (max 40 chars before method prefix)
    if len(clean) > 40:
        clean = clean[:40].rstrip("_")
    if not clean:
        clean = f"step_{index}"
    name = f"{method}_{clean}"
    # Append index to avoid clashes
    return f"{name}_{index}" if index > 0 else name


def _render_action(name: str, req: RecordedRequest) -> str:
    """Render one action function."""
    body_arg = _body_arg(req.request_body)
    expected_status = _status_list(req.status_code)

    lines: list[str] = [
        f"def {name}(api):",
        f'    """Recorded: {req.method} {req.url} → {req.status_code}"""',
        f"    result = api.{req.method.lower()}(",
        f"        {_url_arg(req.url)},",
    ]
    if body_arg:
        lines.append(f"        {body_arg},")
    if req.request_headers:
        filtered = {k: v for k, v in req.request_headers.items()
                    if k.lower() not in ("content-length", "host", "user-agent")}
        if filtered:
            lines.append(f"        headers={_repr(filtered)},")
    lines.append("    )")
    lines.append("    return result")

    # Wrap in Action with expected_status assertion
    action_def = "\n".join(lines)
    action_obj = (
        f"\n{name} = Action(\n"
        f"    name={_repr(name)},\n"
        f"    execute={name},\n"
        f"    expected_status={expected_status},\n"
        ")"
    )
    return action_def + action_obj


def _url_arg(url: str) -> str:
    """Return the path portion as a quoted string."""
    # Strip base URL if present (we only keep the path+query)
    # Split on first '/' after scheme to get path
    if "://" in url:
        parts = url.split("/", 3)
        path = "/" + parts[3] if len(parts) > 3 else "/"
    else:
        path = url
    return repr(path)


def _body_arg(body: Any) -> str:
    """Return a kwargs snippet for the request body, or empty string."""
    if body is None:
        return ""
    if isinstance(body, (dict, list)):
        return f"json={_repr(body)}"
    return f"data={_repr(body)}"


def _status_list(code: int) -> str:
    if code == 0:
        return "None"
    return repr([code])


def _repr(obj: Any) -> str:
    """Return a compact repr of obj, using json.dumps for dicts/lists."""
    if isinstance(obj, (dict, list)):
        try:
            return json.dumps(obj, sort_keys=True)
        except (TypeError, ValueError):
            pass
    return repr(obj)
