# retoor <retoor@molodetz.nl>

from __future__ import annotations

from dataclasses import dataclass, field
from typing import Iterator

from devplacepy import docs_api


@dataclass
class Param:
    name: str
    location: str
    type: str
    required: bool
    description: str
    options: list[str] = field(default_factory=list)


@dataclass
class Method:
    name: str
    http_method: str
    path: str
    title: str
    summary: str
    auth: str
    group: str
    destructive: bool
    params: list[Param]

    @property
    def path_params(self) -> list[Param]:
        return [p for p in self.params if p.location == "path"]

    @property
    def query_params(self) -> list[Param]:
        return [p for p in self.params if p.location == "query"]

    @property
    def body_params(self) -> list[Param]:
        return [p for p in self.params if p.location == "form"]


def _method_name(endpoint_id: str) -> str:
    return endpoint_id.replace("-", ".")


def _to_param(spec: dict) -> Param:
    return Param(
        name=spec["name"],
        location=spec.get("location", "form"),
        type=spec.get("type", "string"),
        required=bool(spec.get("required", False)),
        description=spec.get("description", ""),
        options=list(spec.get("options", []) or []),
    )


def iter_methods() -> Iterator[Method]:
    seen: set[str] = set()
    for group in docs_api.API_GROUPS:
        group_title = group.get("title", group.get("slug", ""))
        for ep in group.get("endpoints", []) or []:
            name = _method_name(ep["id"])
            if name in seen:
                continue
            seen.add(name)
            yield Method(
                name=name,
                http_method=ep["method"].upper(),
                path=ep["path"],
                title=ep.get("title", name),
                summary=ep.get("summary", ""),
                auth=ep.get("auth", "user"),
                group=group_title,
                destructive=bool(ep.get("destructive", False)),
                params=[_to_param(p) for p in ep.get("params", []) or []],
            )


def build_index() -> dict[str, Method]:
    return {method.name: method for method in iter_methods()}


def method_help(method: Method) -> str:
    lines = [
        f"{method.title} - {method.http_method} {method.path}",
        f"Group: {method.group} | Auth: {method.auth}",
        "",
        method.summary,
        "",
        "Call with a single struct of named parameters, for example:",
        f"  proxy.{method.name}({{{_example_struct(method)}}})",
        "",
        "Authenticate by passing 'api_key' inside the struct, or with an "
        "X-API-KEY / Authorization Bearer header on the HTTP transport.",
    ]
    if method.params:
        lines.append("")
        lines.append("Parameters:")
        for p in method.params:
            flag = "required" if p.required else "optional"
            extra = f" (one of: {', '.join(p.options)})" if p.options else ""
            lines.append(
                f"  - {p.name} [{p.location}, {p.type}, {flag}]: {p.description}{extra}"
            )
    return "\n".join(lines)


def method_signature(method: Method) -> list[list[str]]:
    return [["struct", "struct"]]


def _example_struct(method: Method) -> str:
    pieces = [f"'{p.name}': ..." for p in method.params if p.required]
    if method.auth != "public":
        pieces.append("'api_key': ...")
    return ", ".join(pieces)
