from __future__ import annotations

import uuid

import structlog
from sqlalchemy import select
from sqlalchemy.dialects.postgresql import insert
from sqlalchemy.ext.asyncio import AsyncSession

from app.db.models.user import User

log = structlog.get_logger(__name__)


class UserRepository:
    def __init__(self, session: AsyncSession) -> None:
        self._s = session

    async def get_by_telegram_id(self, telegram_id: int) -> User | None:
        result = await self._s.execute(
            select(User).where(User.telegram_id == telegram_id)
        )
        return result.scalar_one_or_none()

    async def get_or_create(self, tg_user_id: int, username: str | None = None) -> User:
        stmt = (
            insert(User)
            .values(telegram_id=tg_user_id, telegram_username=username)
            .on_conflict_do_update(
                index_elements=["telegram_id"],
                set_={"telegram_username": username},
            )
            .returning(User)
        )
        result = await self._s.execute(stmt)
        await self._s.flush()
        row = result.scalar_one()
        return row

    async def get_by_id(self, user_id: uuid.UUID) -> User | None:
        result = await self._s.execute(select(User).where(User.id == user_id))
        return result.scalar_one_or_none()

    async def add_storage_usage(self, user_id: uuid.UUID, bytes_delta: int) -> None:
        user = await self.get_by_id(user_id)
        if user:
            user.storage_used_bytes = max(0, user.storage_used_bytes + bytes_delta)
            await self._s.flush()
