# src/utils/credit_mirror.py
"""원장 DB(DATABASE_URL) 커밋 후 credit_balances / credit_transactions 를 DATABASE_LOCAL_URL 로 복제."""
from __future__ import annotations

import logging
import os
from typing import TYPE_CHECKING, Optional

from sqlalchemy import create_engine, text
from sqlalchemy.engine import Engine

if TYPE_CHECKING:
    from src.models.credit import CreditBalance, CreditTransaction

logger = logging.getLogger(__name__)

_engine: Optional[Engine] = None


def _mirror_enabled() -> bool:
    if not os.getenv("DATABASE_LOCAL_URL", "").strip():
        return False
    return os.getenv("CREDIT_MIRROR_ENABLED", "0").strip().lower() in ("1", "true", "yes")


def _get_engine() -> Optional[Engine]:
    global _engine
    if not _mirror_enabled():
        return None
    if _engine is None:
        url = os.getenv("DATABASE_LOCAL_URL", "").strip()
        _engine = create_engine(url, pool_pre_ping=True, pool_recycle=3600)
    return _engine


def mirror_credit_balance_row(balance: "CreditBalance") -> None:
    """credit_balances 단일 행 upsert (user_id 기준)."""
    eng = _get_engine()
    if not eng or balance is None:
        return
    try:
        with eng.begin() as conn:
            conn.execute(
                text(
                    """
                    INSERT INTO credit_balances (
                        user_id, total_credit, free_credit, event_credit,
                        daily_renewal_credit, subscription_credit, add_on_credit,
                        last_daily_renewal, updated_at
                    ) VALUES (
                        :user_id, :total_credit, :free_credit, :event_credit,
                        :daily_renewal_credit, :subscription_credit, :add_on_credit,
                        :last_daily_renewal, :updated_at
                    )
                    ON DUPLICATE KEY UPDATE
                        total_credit = VALUES(total_credit),
                        free_credit = VALUES(free_credit),
                        event_credit = VALUES(event_credit),
                        daily_renewal_credit = VALUES(daily_renewal_credit),
                        subscription_credit = VALUES(subscription_credit),
                        add_on_credit = VALUES(add_on_credit),
                        last_daily_renewal = VALUES(last_daily_renewal),
                        updated_at = VALUES(updated_at)
                    """
                ),
                {
                    "user_id": balance.user_id,
                    "total_credit": int(balance.total_credit or 0),
                    "free_credit": int(balance.free_credit or 0),
                    "event_credit": int(balance.event_credit or 0),
                    "daily_renewal_credit": int(balance.daily_renewal_credit or 0),
                    "subscription_credit": int(balance.subscription_credit or 0),
                    "add_on_credit": int(balance.add_on_credit or 0),
                    "last_daily_renewal": balance.last_daily_renewal,
                    "updated_at": balance.updated_at,
                },
            )
    except Exception as e:
        logger.warning("credit_mirror balance 실패 user_id=%s: %s", getattr(balance, "user_id", None), e)


def mirror_credit_transaction_row(txn: "CreditTransaction") -> None:
    """credit_transactions 단일 행 upsert (id 기준으로 원장과 동일 PK 유지)."""
    eng = _get_engine()
    if not eng or txn is None or txn.id is None:
        return
    try:
        ct = txn.credit_type.value if txn.credit_type else None
        with eng.begin() as conn:
            conn.execute(
                text(
                    """
                    INSERT INTO credit_transactions (
                        id, user_id, credit_type, amount, balance_after,
                        description, reference_id, reference_type, meta_data,
                        created_at, event_expiry_date
                    ) VALUES (
                        :id, :user_id, :credit_type, :amount, :balance_after,
                        :description, :reference_id, :reference_type, :meta_data,
                        :created_at, :event_expiry_date
                    )
                    ON DUPLICATE KEY UPDATE
                        user_id = VALUES(user_id),
                        credit_type = VALUES(credit_type),
                        amount = VALUES(amount),
                        balance_after = VALUES(balance_after),
                        description = VALUES(description),
                        reference_id = VALUES(reference_id),
                        reference_type = VALUES(reference_type),
                        meta_data = VALUES(meta_data),
                        created_at = VALUES(created_at),
                        event_expiry_date = VALUES(event_expiry_date)
                    """
                ),
                {
                    "id": txn.id,
                    "user_id": txn.user_id,
                    "credit_type": ct,
                    "amount": int(txn.amount),
                    "balance_after": int(txn.balance_after),
                    "description": txn.description,
                    "reference_id": txn.reference_id,
                    "reference_type": txn.reference_type,
                    "meta_data": txn.meta_data,
                    "created_at": txn.created_at,
                    "event_expiry_date": txn.event_expiry_date,
                },
            )
    except Exception as e:
        logger.warning("credit_mirror transaction id=%s 실패: %s", txn.id, e)


def mirror_balance_and_transactions(
    user_id: str,
    balance: Optional["CreditBalance"] = None,
    transactions: Optional[list] = None,
) -> None:
    """커밋 직후 호출: 잔액 + (선택) 거래 행들을 로컬 DB에 반영."""
    if not _mirror_enabled():
        return
    from src.models.credit import CreditBalance

    b = balance
    if b is None:
        b = CreditBalance.query.filter_by(user_id=user_id).first()
    if b is not None:
        mirror_credit_balance_row(b)
    if transactions:
        for t in transactions:
            if t is not None:
                mirror_credit_transaction_row(t)
