"""Swagger (OpenAPI v2) → UAP Tool list parser.

This adapter converts a Swagger 2.0 document that is already loaded into a Python
``dict`` into one or more :class:`unifiedagentprotocol.models.tool.Tool` objects.

The conversion rules mirror those in ``parser.openapi`` but apply to the older
specification format:
* Parameters are defined as a list with *location* (query, path, body, ...).
* A successful response is identified via status code ``200``.

NOTE: This is intentionally minimal but covers typical documents generated by
common toolchains.
"""
from __future__ import annotations

from typing import Any, Dict, List

from unifiedagentprotocol.models.tool import Tool, ToolParam, OutputSchema
from unifiedagentprotocol.models.common import Trigger

HTTP_METHODS = {"get", "post", "put", "patch", "delete", "options", "head"}


def _schema_props_to_params(schema: Dict[str, Any], required: List[str]) -> List[ToolParam]:
    """Convert a JSON-Schema object properties mapping → list[ToolParam]."""
    params: List[ToolParam] = []
    for name, prop in schema.get("properties", {}).items():
        params.append(
            ToolParam(
                name=name,
                type=prop.get("type", "string"),
                required=name in required,
                description=prop.get("description"),
                default=prop.get("default"),
                enum=prop.get("enum"),
            )
        )
    return params


def parse_swagger(spec: Dict[str, Any]) -> List[Tool]:
    """Convert a Swagger 2.0 spec into a list of UAP ``Tool`` definitions."""

    if spec.get("swagger") != "2.0":
        raise ValueError("Only Swagger 2.0 documents are supported")

    tools: List[Tool] = []
    base_description = spec.get("info", {}).get("description", "")

    for path, path_item in spec.get("paths", {}).items():
        for method, op in path_item.items():
            if method.lower() not in HTTP_METHODS:
                continue

            op_id = op.get("operationId") or f"{method}_{path.strip('/').replace('/', '_')}"
            description = op.get("description") or op.get("summary") or base_description

            parameters: List[ToolParam] = []

            # Collect parameters from the "parameters" array (path-, query-, body-level)
            for p in op.get("parameters", []):
                if p.get("in") == "body":
                    schema = p.get("schema", {})
                    parameters.extend(_schema_props_to_params(schema, schema.get("required", [])))
                else:
                    parameters.append(
                        ToolParam(
                            name=p.get("name"),
                            type=p.get("type", "string"),
                            required=p.get("required", False),
                            description=p.get("description"),
                            default=p.get("default"),
                            enum=p.get("enum"),
                        )
                    )

            # Output schema from 200 response
            output = None
            responses = op.get("responses", {})
            if "200" in responses:
                schema = responses["200"].get("schema", {})
                if schema:
                    output = OutputSchema(schema=schema)

            tools.append(
                Tool(
                    name=op_id,
                    description=description or "",
                    parameters=parameters,
                    output=output,
                    triggers=[Trigger(type="manual")],
                    metadata={"method": method.upper(), "path": path},
                )
            )

    return tools
