# RESUME-01: Exchange gap floor clamping for sidecar resume TID
"""Clamp resume TIDs above known exchange gaps from kintsugi_log.

Exchange gaps are permanent TID ranges where the exchange had no trades
(verified by kintsugi with checksum-verified Parquet). There are only 2
known exchange gaps across all history, but the guard prevents the sidecar
from wasting REST API calls on ranges that will always return 0 trades.
"""

from __future__ import annotations

import logging
from typing import TYPE_CHECKING

if TYPE_CHECKING:
    from opendeviationbar.clickhouse.cache import OpenDeviationBarCache

logger = logging.getLogger(__name__)


def _clamp_resume_tid_above_exchange_gaps(
    ch_cache: OpenDeviationBarCache,
    resume_tids: dict[str, int | None],
) -> dict[str, int | None]:
    """Clamp resume TIDs above known exchange gaps from kintsugi_log.

    Queries the highest ``ariadne_from_id`` per symbol from kintsugi_log
    entries with ``result = 'exchange_gap'``. If the exchange gap TID is
    above the current resume TID for a symbol, the resume TID is raised
    to skip the unfillable range.

    Non-fatal: if the query fails, returns *resume_tids* unchanged so
    the sidecar can still start.
    """
    try:
        result = ch_cache.client.query(
            "SELECT symbol, max(ariadne_from_id) AS max_gap_tid "
            "FROM opendeviationbar_cache.kintsugi_log "
            "WHERE result = 'exchange_gap' AND ariadne_from_id > 0 "
            "GROUP BY symbol"
        )
        gap_floors: dict[str, int] = {
            row[0]: row[1] for row in result.result_rows
        }
    except (OSError, RuntimeError, ConnectionError):
        logger.warning(
            "aion: exchange gap floor query failed (non-fatal, proceeding "
            "with unclamped resume TIDs)",
            exc_info=True,
        )
        return resume_tids

    if not gap_floors:
        return resume_tids

    clamped = dict(resume_tids)
    for sym, floor_tid in gap_floors.items():
        current = clamped.get(sym)
        if current is not None and floor_tid > current:
            logger.info(
                "aion %s: resume_tid clamped %d -> %d "
                "(exchange gap floor from kintsugi_log)",
                sym,
                current,
                floor_tid,
            )
            clamped[sym] = floor_tid

    return clamped
