"""YAML utilities - stdlib-only serialization and parsing."""

from __future__ import annotations

import json
from typing import Any


def to_yaml(obj: Any, indent: int = 0) -> str:
    """Convert Python object to YAML string (simple implementation)."""
    prefix = "  " * indent

    if obj is None:
        return "null"
    elif isinstance(obj, bool):
        return "true" if obj else "false"
    elif isinstance(obj, (int, float)):
        return str(obj)
    elif isinstance(obj, str):
        # Check if needs quoting
        if any(
            c in obj
            for c in [
                ":",
                "#",
                "{",
                "}",
                "[",
                "]",
                ",",
                "&",
                "*",
                "?",
                "|",
                "-",
                "<",
                ">",
                "=",
                "!",
                "%",
                "@",
                "`",
                "\n",
            ]
        ):
            # Use double quotes and escape
            escaped = obj.replace("\\", "\\\\").replace('"', '\\"').replace("\n", "\\n")
            return f'"{escaped}"'
        elif obj == "" or obj.startswith(" ") or obj.endswith(" "):
            return f'"{obj}"'
        return obj
    elif isinstance(obj, list):
        if not obj:
            return "[]"
        lines = []
        for item in obj:
            if isinstance(item, (dict, list)):
                lines.append(f"{prefix}-")
                lines.append(to_yaml(item, indent + 1))
            else:
                lines.append(f"{prefix}- {to_yaml(item)}")
        return "\n".join(lines)
    elif isinstance(obj, dict):
        if not obj:
            return "{}"
        lines = []
        for key, value in obj.items():
            if isinstance(value, (dict, list)) and value:
                lines.append(f"{prefix}{key}:")
                lines.append(to_yaml(value, indent + 1))
            else:
                lines.append(f"{prefix}{key}: {to_yaml(value)}")
        return "\n".join(lines)
    else:
        return str(obj)


def parse_yaml_simple(content: str) -> dict:
    """Parse simple YAML content (for reading manifest files).

    This is a simplified parser for the YAML we generate.
    Handles: scalars, nested dicts, lists (both inline and YAML-style).
    """
    result: dict[str, Any] = {}
    # Stack: (container, indent, pending_key, container_is_list_item)
    stack: list[tuple[Any, int, str | None, bool]] = [(result, -1, None, False)]

    lines = content.split("\n")
    i = 0
    while i < len(lines):
        line = lines[i]
        if not line.strip() or line.strip().startswith("#"):
            i += 1
            continue

        # Calculate indent
        stripped = line.lstrip()
        indent = len(line) - len(stripped)

        # Pop stack for dedents (but keep at least root)
        while len(stack) > 1 and stack[-1][1] >= indent:
            stack.pop()

        current_container, current_indent, pending_key, is_list_item = stack[-1]

        # Handle bare list item marker "-" (no content on same line)
        if stripped == "-":
            # Next lines contain the item's content as a nested dict
            new_item: dict[str, Any] = {}
            if isinstance(current_container, dict) and pending_key:
                if pending_key not in current_container:
                    current_container[pending_key] = []
                current_container[pending_key].append(new_item)
            stack.append((new_item, indent, None, True))
            i += 1
            continue

        # Handle list items with content "- value" or "- key: value"
        if stripped.startswith("- "):
            value = stripped[2:].strip()

            # Check if this is a list item with nested content
            if ":" in value and not value.startswith('"'):
                # This is a dict item in a list
                item_key, _, item_val = value.partition(":")
                item_key = item_key.strip()
                item_val = item_val.strip()

                # Parse the item value
                parsed_val: Any
                if item_val.startswith('"') and item_val.endswith('"'):
                    parsed_val = item_val[1:-1]
                elif item_val.lower() == "true":
                    parsed_val = True
                elif item_val.lower() == "false":
                    parsed_val = False
                elif item_val.lower() == "null" or item_val == "":
                    parsed_val = None
                else:
                    try:
                        parsed_val = int(item_val)
                    except ValueError:
                        try:
                            parsed_val = float(item_val)
                        except ValueError:
                            parsed_val = item_val

                new_item = {item_key: parsed_val}

                # Attach to parent's pending key as list
                if isinstance(current_container, dict) and pending_key:
                    if pending_key not in current_container:
                        current_container[pending_key] = []
                    current_container[pending_key].append(new_item)
                    # Push this item dict for potential nested content
                    stack.append((new_item, indent, item_key, True))
            else:
                # Simple list item (string value)
                # Remove quotes if present
                if value.startswith('"') and value.endswith('"'):
                    value = value[1:-1]

                # Attach to parent's pending key
                if isinstance(current_container, dict) and pending_key:
                    if pending_key not in current_container:
                        current_container[pending_key] = []
                    current_container[pending_key].append(value)

            i += 1
            continue

        # Parse key: value
        if ":" in stripped:
            key, _, value = stripped.partition(":")
            key = key.strip()
            value = value.strip()

            if value == "" or value == "|":
                # Check what follows
                if i + 1 < len(lines):
                    next_line = lines[i + 1]
                    next_stripped = next_line.lstrip()
                    next_indent = len(next_line) - len(next_stripped)

                    if next_indent > indent:
                        if value == "|":
                            # Multiline string
                            multi_lines = []
                            i += 1
                            while i < len(lines):
                                ml = lines[i]
                                ml_indent = len(ml) - len(ml.lstrip())
                                if ml.strip() and ml_indent <= indent:
                                    break
                                multi_lines.append(ml.strip())
                                i += 1
                            current_container[key] = "\n".join(multi_lines)
                            continue
                        elif next_stripped.startswith("-"):
                            # Following content is a list
                            current_container[key] = []
                            stack.append((current_container, indent, key, False))
                        else:
                            # Following content is a nested dict
                            current_container[key] = {}
                            stack.append((current_container[key], indent, None, False))
                    else:
                        current_container[key] = None
                else:
                    current_container[key] = None
            elif value.startswith("[") and value.endswith("]"):
                # Inline list
                try:
                    current_container[key] = json.loads(value)
                except json.JSONDecodeError:
                    current_container[key] = value
            elif value.startswith('"') and value.endswith('"'):
                current_container[key] = value[1:-1]
            elif value.lower() == "true":
                current_container[key] = True
            elif value.lower() == "false":
                current_container[key] = False
            elif value.lower() == "null":
                current_container[key] = None
            else:
                try:
                    current_container[key] = int(value)
                except ValueError:
                    try:
                        current_container[key] = float(value)
                    except ValueError:
                        current_container[key] = value

        i += 1

    return result
