"""Infer LAPIS [flows] from OpenAPI ``links`` and extensions."""

from __future__ import annotations

from typing import Any

from lapis_spec.models.lapis import LapisFlow
from lapis_spec.models.openapi import OpenAPIDict


def convert_flows(doc: OpenAPIDict) -> list[LapisFlow]:
    """Build LAPIS flows from OpenAPI ``links`` and ``x-flows`` extensions.

    Links provide the closest mapping to LAPIS flows.  If ``x-flows``
    is present, it takes precedence.
    """
    flows_ext = doc.get("x-flows")
    if isinstance(flows_ext, list):
        return _from_extension(flows_ext)
    if isinstance(flows_ext, dict):
        return _from_extension_dict(flows_ext)

    return _from_links(doc)


def _from_extension(flows: list[Any]) -> list[LapisFlow]:
    result: list[LapisFlow] = []
    for entry in flows:
        if not isinstance(entry, dict):
            continue
        name = entry.get("name", "unnamed_flow")
        desc = entry.get("description", "")
        chain = entry.get("chain", "")
        narrative = entry.get("narrative")
        result.append(
            LapisFlow(name=name, description=desc, chain=chain, narrative=narrative)
        )
    return result


def _from_extension_dict(flows: dict[str, Any]) -> list[LapisFlow]:
    result: list[LapisFlow] = []
    for name, entry in flows.items():
        if not isinstance(entry, dict):
            continue
        desc = entry.get("description", "")
        chain = entry.get("chain", "")
        narrative = entry.get("narrative")
        result.append(
            LapisFlow(name=name, description=desc, chain=chain, narrative=narrative)
        )
    return result


def _from_links(doc: OpenAPIDict) -> list[LapisFlow]:
    """Extract flows from OpenAPI ``responses.*.links``."""
    paths = doc.get("paths", {})
    link_chains: dict[str, list[str]] = {}

    for _path, path_item in paths.items():
        if not isinstance(path_item, dict):
            continue
        for method in ("get", "post", "put", "patch", "delete"):
            op = path_item.get(method)
            if not isinstance(op, dict):
                continue
            op_id = op.get("operationId", "")
            responses = op.get("responses", {})
            for _code, resp in responses.items():
                if not isinstance(resp, dict):
                    continue
                links = resp.get("links", {})
                for _link_name, link_data in links.items():
                    if not isinstance(link_data, dict):
                        continue
                    target = link_data.get("operationId", "")
                    if op_id and target:
                        link_chains.setdefault(op_id, []).append(target)

    if not link_chains:
        return []

    flows: list[LapisFlow] = []
    for source, targets in link_chains.items():
        chain = " -> ".join([source, *targets])
        flows.append(
            LapisFlow(
                name=f"{source}_flow",
                description=f"Flow from {source}",
                chain=chain,
            )
        )
    return flows
