from typing import List, Optional, Tuple

from pydantic import EmailStr
from sqlalchemy import select

from app.core.database import db
from app.models.user import User
from app.repositories.base import BaseRepository
from app.schemas.base import Pager


class UserRepository(BaseRepository[User]):
    model = User

    async def get_by_username(self, username: str) -> Optional[User]:
        async with db.session() as session:
            result = await session.execute(
                select(self.model).where(self.model.username == username)
            )
            return result.scalar_one_or_none()

    async def get_by_email(self, email: EmailStr) -> Optional[User]:
        async with db.session() as session:
            result = await session.execute(
                select(self.model).where(self.model.email == email)
            )
            return result.scalar_one_or_none()

    async def get_users(
        self,
        username: Optional[str] = None,
        pager: Optional[Pager] = None,
        order_by: Optional[str] = "-created_at",
    ) -> Tuple[List[User], int]:
        if username:
            query = select(self.model).where(self.model.username.contains(username))
        else:
            query = select(self.model)
        return await self._paginate(query, pager, order_by)

    async def create_user(
        self,
        username: str,
        email: EmailStr,
        hashed_password: str,
    ) -> User:
        return await self.create(
            username=username,
            email=email,
            hashed_password=hashed_password,
        )

    async def batch_get_by_ids(self, ids: List[int]) -> List[User]:
        async with db.session() as session:
            result = await session.execute(
                select(self.model).where(self.model.id.in_(ids))
            )
            return list(result.scalars().all())
