"""Telegram service utilities — chat persistence helpers."""

from sqlalchemy.dialects.sqlite import insert as sqlite_insert
from sqlmodel.ext.asyncio.session import AsyncSession

from ..database.models import TelegramChat


async def save_chat_from_webhook(
    session: AsyncSession, bot_id: int, chat_data: dict,
    language_code: str = "",
) -> None:
    """Save or update a chat entry from an incoming webhook message.

    Called by the webhook handler to auto-persist chats. Uses a single
    ``INSERT ... ON CONFLICT DO UPDATE`` keyed on the
    ``uq_telegram_chat_bot_chat`` unique constraint so two concurrent
    webhook deliveries cannot race a check-then-insert and produce
    duplicate rows. Only mutable display/identity fields are updated on
    conflict — ``commands_enabled``, ``language_override``, and
    ``discovered_at`` belong to the user / first discovery and stay sticky.
    """
    chat_id = str(chat_data.get("id", ""))
    if not chat_id:
        return

    title = chat_data.get("title") or (
        chat_data.get("first_name", "") + (" " + chat_data.get("last_name", "")).strip()
    )
    chat_type = chat_data.get("type", "private")
    username = chat_data.get("username", "")

    # Only the SQLite dialect path is wired up — the deployed default. A
    # future Postgres backend would need pg_insert here; the unique
    # constraint name is dialect-portable so the same conflict_target works.
    stmt = sqlite_insert(TelegramChat).values(
        bot_id=bot_id,
        chat_id=chat_id,
        title=title,
        chat_type=chat_type,
        username=username,
        language_code=language_code,
    )
    update_cols: dict = {
        "title": title,
        "chat_type": chat_type,
        "username": username,
    }
    # Only overwrite language_code when the inbound payload carries one,
    # otherwise we'd clobber a previously-detected locale with empty.
    if language_code:
        update_cols["language_code"] = language_code
    stmt = stmt.on_conflict_do_update(
        index_elements=["bot_id", "chat_id"],
        set_=update_cols,
    )
    # session.execute (not exec) — exec is the SQLModel/Select wrapper that
    # rejects raw Core Insert statements.
    await session.execute(stmt)
