"""Shared utilities used across kintsugi submodules."""

from __future__ import annotations

import threading
from pathlib import Path
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from opendeviationbar.config.kintsugi import KintsugiConfig

# ---------------------------------------------------------------------------
# NDJSON telemetry (persists independently of ClickHouse)
# ---------------------------------------------------------------------------

_KINTSUGI_LOG_DIR = Path.home() / "opendeviationbar-py" / "logs"
_KINTSUGI_NDJSON = _KINTSUGI_LOG_DIR / "kintsugi.ndjson"

# ---------------------------------------------------------------------------
# Repair configuration — SSoT in config/kintsugi.py
# ---------------------------------------------------------------------------


def _kintsugi_cfg() -> KintsugiConfig:
    from opendeviationbar.config.kintsugi import KintsugiConfig
    return KintsugiConfig()


# ---------------------------------------------------------------------------
# Thread-local CH cache (Issue #279 — eliminates per-call connection overhead)
# ---------------------------------------------------------------------------

_thread_local = threading.local()


def _get_worker_cache():  # noqa: ANN202
    """Get or create a thread-local OpenDeviationBarCache.

    Each worker thread gets ONE cache for its lifetime, eliminating
    per-call connection overhead (urllib3.PoolManager with 20 fds each).
    Pattern proven in scripts/repair_direct_parquet.py at 24 workers.
    """
    cache = getattr(_thread_local, "cache", None)
    if cache is None:
        from opendeviationbar.clickhouse.cache import OpenDeviationBarCache

        _thread_local.cache = OpenDeviationBarCache()
        cache = _thread_local.cache
    return cache


# Transient error patterns — don't count toward max attempts (Issue #156)
_TRANSIENT_ERROR_PATTERNS = (
    "timeout",
    "connection",
    "rate limit",
    "503",
    "502",
    "500",
    "network",
    "timed out",
    "reset by peer",
)


def _get_mode_for_symbol(symbol: str) -> str:
    """Get ouroboros_mode for a symbol from the registry.

    Returns "aion" as safe default for unknown symbols.
    """
    from opendeviationbar.symbol_registry import get_symbol_entries

    entries = get_symbol_entries()
    entry = entries.get(symbol)
    if entry is None:
        return "aion"
    return entry.ouroboros_mode.value


def _is_transient_error(error_message: str) -> bool:
    """Check if an error message indicates a transient (retriable) failure.

    Transient errors (network, timeout, rate limit, server errors) should
    not count toward the per-shard max attempt limit (Issue #156).
    """
    lower = error_message.lower()
    return any(pattern in lower for pattern in _TRANSIENT_ERROR_PATTERNS)
