"""Flatten nested body_example values into PARAM drawer fields."""

from __future__ import annotations

from typing import Any


def body_fields_from_example(body_example: dict[str, Any] | None) -> list[dict[str, Any]]:
    """PARAM inputs derived from body_example, including nested scalar paths.

    Nested objects/arrays become dotted paths (``placement.host``, ``cpu.count``,
    ``disks.0.new_vmdk.name``) so the Params drawer can edit leaves while the
    request body keeps the full nested JSON.
    """

    if not isinstance(body_example, dict) or not body_example:
        return []

    fields: list[dict[str, Any]] = []

    def _leaf_type(value: Any) -> str:
        if isinstance(value, bool):
            return "boolean"
        if isinstance(value, int) and not isinstance(value, bool):
            return "integer"
        if isinstance(value, float):
            return "number"
        return "string"

    def _walk(prefix: str, value: Any) -> None:
        if isinstance(value, dict):
            for key, child in value.items():
                path = f"{prefix}.{key}" if prefix else str(key)
                _walk(path, child)
            return
        if isinstance(value, list):
            for index, child in enumerate(value):
                path = f"{prefix}.{index}" if prefix else str(index)
                _walk(path, child)
            return
        fields.append(
            {
                "name": prefix,
                "type": _leaf_type(value),
                "description": prefix,
                "optional": True,
                "enum": [],
                "example": value,
            }
        )

    _walk("", body_example)
    return fields


def set_by_path(root: dict[str, Any], path: str, value: Any) -> None:
    """Assign ``value`` at a dotted path, creating intermediate dicts/lists."""

    parts = [part for part in str(path).split(".") if part]
    if not parts:
        return
    cur: Any = root
    for index, part in enumerate(parts[:-1]):
        nxt = parts[index + 1]
        want_list = nxt.isdigit()
        if isinstance(cur, list):
            idx = int(part)
            while len(cur) <= idx:
                cur.append([] if want_list else {})
            if cur[idx] is None or not isinstance(cur[idx], (dict, list)):
                cur[idx] = [] if want_list else {}
            cur = cur[idx]
            continue
        if part not in cur or not isinstance(cur[part], (dict, list)):
            cur[part] = [] if want_list else {}
        cur = cur[part]
    last = parts[-1]
    if isinstance(cur, list):
        idx = int(last)
        while len(cur) <= idx:
            cur.append(None)
        cur[idx] = value
    else:
        cur[last] = value


__all__ = ["body_fields_from_example", "set_by_path"]
