"""Flexible Pydantic types for MCP tool parameters.

MCP clients using HTTP transport often serialize complex types (lists, dicts)
as JSON strings instead of native Python objects. These annotated types
automatically parse JSON strings during Pydantic validation.

Usage:
    from testio_mcp.schemas.flexible_types import FlexibleIntList, FlexibleDict

    @mcp.tool()
    async def my_tool(
        product_ids: FlexibleIntList,  # Accepts [1,2], "1,2", "[1,2]", 1
        filters: FlexibleDict | None,  # Accepts {"k": "v"} or '{"k": "v"}'
    ) -> dict: ...

Benefits:
- Declarative: Type annotation handles parsing automatically
- Type-safe: mypy understands the resolved types
- Consistent: All tools use the same parsing logic
- Testable: Parsing logic centralized in parsing.py
"""

from typing import Annotated, Any

from pydantic import BeforeValidator

from testio_mcp.utilities.parsing import (
    parse_dict_input,
    parse_int_list_input,
    parse_list_input,
)


def _parse_int_list_or_raise(value: Any) -> list[int]:
    """Parse int list, raising ValueError for None result.

    BeforeValidator wrapper that ensures we always return list[int],
    converting None to empty list for required fields.
    """
    result = parse_int_list_input(value)
    if result is None:
        return []
    return result


def _parse_int_list_optional(value: Any) -> list[int] | None:
    """Parse int list, allowing None result."""
    return parse_int_list_input(value)


def _parse_str_list_or_raise(value: Any) -> list[str]:
    """Parse string list, raising ValueError for None result."""
    result = parse_list_input(value)
    if result is None:
        return []
    return result


def _parse_str_list_optional(value: Any) -> list[str] | None:
    """Parse string list, allowing None result."""
    return parse_list_input(value)


def _parse_dict_or_raise(value: Any) -> dict[str, Any]:
    """Parse dict, raising ValueError for None result."""
    result = parse_dict_input(value)
    if result is None:
        return {}
    return result


def _parse_dict_optional(value: Any) -> dict[str, Any] | None:
    """Parse dict, allowing None result."""
    return parse_dict_input(value)


# =============================================================================
# Flexible Integer List Types
# =============================================================================

FlexibleIntList = Annotated[list[int], BeforeValidator(_parse_int_list_or_raise)]
"""Flexible integer list that accepts multiple input formats.

Accepts:
- Python list of ints: [598, 599]
- Python list of strings: ["598", "599"]
- Single int: 598
- Single string: "598"
- JSON array string: "[598, 599]"
- Comma-separated string: "598,599"

Returns empty list for None/empty input (use FlexibleIntListOptional for None).

Examples:
    product_ids: FlexibleIntList  # Required, returns [] if empty
"""

FlexibleIntListOptional = Annotated[list[int] | None, BeforeValidator(_parse_int_list_optional)]
"""Optional flexible integer list that can be None.

Same parsing as FlexibleIntList, but returns None for empty input.

Examples:
    test_ids: FlexibleIntListOptional = None  # Optional, None if not provided
"""


# =============================================================================
# Flexible String List Types
# =============================================================================

FlexibleStrList = Annotated[list[str], BeforeValidator(_parse_str_list_or_raise)]
"""Flexible string list that accepts multiple input formats.

Accepts:
- Python list: ["critical", "high"]
- JSON array string: '["critical", "high"]'
- Comma-separated string: "critical,high"

Returns empty list for None/empty input.

Examples:
    severities: FlexibleStrList  # Required
"""

FlexibleStrListOptional = Annotated[list[str] | None, BeforeValidator(_parse_str_list_optional)]
"""Optional flexible string list that can be None.

Examples:
    statuses: FlexibleStrListOptional = None  # Optional
"""


# =============================================================================
# Flexible Dictionary Types
# =============================================================================

FlexibleDict = Annotated[dict[str, Any], BeforeValidator(_parse_dict_or_raise)]
"""Flexible dictionary that accepts dict or JSON string.

Accepts:
- Python dict: {"product_id": 598}
- JSON object string: '{"product_id": 598}'

Returns empty dict for None/empty input.

Examples:
    filters: FlexibleDict  # Required, returns {} if empty
"""

FlexibleDictOptional = Annotated[dict[str, Any] | None, BeforeValidator(_parse_dict_optional)]
"""Optional flexible dictionary that can be None.

Same parsing as FlexibleDict, but returns None for empty input.

Examples:
    filters: FlexibleDictOptional = None  # Optional, None if not provided
"""
