"""Render a formula token list into an expression string.

The formula list is a mix of string fragments and ``{is_field, field}``
reference dicts. This module:

1. walks the list,
2. resolves each field reference against the record (via the supplied
   resolver function that owns DB access + field-type handling),
3. formats the resolved value into an expression-string literal,
4. concatenates everything into a single expression for ``simpleeval``.
"""
from datetime import date, datetime
from typing import Any, Awaitable, Callable, Dict, List


def format_value_for_expr(value: Any) -> str:
    """Convert a resolved value into an expression-string literal.

    Numbers stay numeric. Strings get double-quoted (escapes preserved).
    Booleans become Python literals. Lists become Python list literals so
    ``IN(field, [...])`` works.
    """
    if isinstance(value, bool):
        return "True" if value else "False"
    if isinstance(value, (int, float)):
        return str(value)
    if isinstance(value, datetime):
        return f'"{value.isoformat()}"'
    if isinstance(value, date):
        return f'"{value.isoformat()}"'
    if isinstance(value, str):
        escaped = value.replace("\\", "\\\\").replace('"', '\\"')
        return f'"{escaped}"'
    if isinstance(value, list):
        return "[" + ", ".join(format_value_for_expr(v) for v in value) + "]"
    return f'"{str(value)}"'


async def render_formula(
    formula: List[Any],
    record: Dict[str, Any],
    resolve_field_token: Callable[[Dict[str, Any], Dict[str, Any]], Awaitable[Any]],
) -> str:
    """Walk the formula list and produce the full expression string.

    ``resolve_field_token(token_dict, record)`` is an async callable owned by
    the caller (handlers.py) that returns the resolved value for a field
    reference. It may raise ``MissingFieldError`` for required-but-missing
    fields; rendering propagates that to the caller unchanged.
    """
    parts: List[str] = []
    for item in formula:
        if isinstance(item, str):
            parts.append(item)
            continue
        if isinstance(item, dict) and item.get("is_field"):
            resolved = await resolve_field_token(item, record)
            parts.append(format_value_for_expr(resolved))
            continue
        raise ValueError(f"Unsupported token shape in formula: {item!r}")
    return "".join(parts)
