from contextlib import contextmanager
import time
import logging
import mysql.connector
from config import DB_CONFIG

logger = logging.getLogger('AI_Strategy')

# Параметры retry для устойчивости к временным сбоям сети/DNS.
# Audit 2026-08-03: bulk retrain ALL тикеров упал на 7 из 18 из-за
# 'Can't connect to MySQL server' (Errno -3: name resolution) и
# 'Lost connection' (Errno 104). Добавлены up to 3 retries с backoff.
DB_MAX_RETRIES = 3
DB_RETRY_BACKOFF_SEC = 2.0  # 2s, 4s, 8s


@contextmanager
def get_connection():
    """Yields MySQL connection с автоматическим retry на сбой сети.

    Audit 2026-08-03: добавлены до 3 retry с экспоненциальным backoff
    (2s → 4s → 8s). Ловит только сетевые ошибки (mysql.connector.Error
    с кодами из Network* и Interface* категорий). Логические ошибки
    (например, дубликат PK) сразу прокидываются выше.
    """
    last_exc = None
    for attempt in range(DB_MAX_RETRIES):
        try:
            conn = mysql.connector.connect(**DB_CONFIG)
            break
        except mysql.connector.Error as e:
            last_exc = e
            # Коды сетевых ошибок, которые разумно ретраить
            retryable = (
                e.errno in (2003, 2006, 2013, 2055)  # connect/lost connection
                or 'name resolution' in str(e).lower()
                or 'connection reset' in str(e).lower()
                or 'wrong version number' in str(e).lower()
            )
            if not retryable or attempt == DB_MAX_RETRIES - 1:
                raise
            wait_sec = DB_RETRY_BACKOFF_SEC * (2 ** attempt)
            logger.warning(
                f"get_connection: attempt {attempt+1}/{DB_MAX_RETRIES} failed: "
                f"{type(e).__name__}: {str(e)[:120]} — retry in {wait_sec}s"
            )
            time.sleep(wait_sec)
    else:
        raise last_exc

    try:
        yield conn
        conn.commit()
    except Exception:
        conn.rollback()
        raise
    finally:
        conn.close()
