from __future__ import annotations

from typing import Any

from .errors import QingflowApiError


JS_MAX_SAFE_INTEGER = 9_007_199_254_740_991


def stringify_backend_id(value: Any) -> str | None:
    """Return an exact public id string for backend-originated identifiers."""
    if value in (None, ""):
        return None
    if isinstance(value, bool):
        return None
    text = str(value).strip()
    return text or None


def normalize_positive_id_text(value: Any, *, field_name: str) -> str:
    """Normalize a user-supplied id while rejecting JS-unsafe numeric input."""
    if value in (None, "") or isinstance(value, bool):
        raise QingflowApiError.config_error(f"{field_name} must be positive")
    if isinstance(value, int):
        if value <= 0:
            raise QingflowApiError.config_error(f"{field_name} must be positive")
        if value > JS_MAX_SAFE_INTEGER:
            raise QingflowApiError.config_error(
                f"{field_name} exceeds JavaScript's safe integer range; pass it as a string to avoid precision loss"
            )
        return str(value)
    if isinstance(value, str):
        text = value.strip()
        if not text.isdecimal() or int(text) <= 0:
            raise QingflowApiError.config_error(f"{field_name} must be a positive integer string")
        return text
    raise QingflowApiError.config_error(f"{field_name} must be a positive integer string")


def normalize_positive_id_int(value: Any, *, field_name: str) -> int:
    """Normalize an id to Python int after the public boundary preserves it as text."""
    return int(normalize_positive_id_text(value, field_name=field_name))


def ids_equal(left: Any, right: Any) -> bool:
    left_text = stringify_backend_id(left)
    right_text = stringify_backend_id(right)
    return left_text is not None and right_text is not None and left_text == right_text
