"""Artist repository — adapter over ``AsyncSession``."""

import uuid

from sqlalchemy import func, select
from sqlalchemy.ext.asyncio import AsyncSession

from app.domain.entities.track import Artist
from app.infrastructure.db.models.album import AlbumModel
from app.infrastructure.db.models.artist import ArtistModel
from app.infrastructure.db.models.track import TrackModel


def _to_entity(row: ArtistModel) -> Artist:
    return Artist(
        id=row.id,
        name=row.name,
        created_at=row.created_at,
        updated_at=row.updated_at,
    )


class SqlAlchemyArtistRepository:
    def __init__(self, session: AsyncSession) -> None:
        self._session = session

    async def get_or_create(self, name: str) -> Artist:
        row = (
            await self._session.execute(select(ArtistModel).where(ArtistModel.name == name))
        ).scalar_one_or_none()
        if row is None:
            row = ArtistModel(name=name)
            self._session.add(row)
            await self._session.flush()
            await self._session.refresh(row)
        return _to_entity(row)

    async def get_by_id(self, artist_id: uuid.UUID) -> Artist | None:
        row = await self._session.get(ArtistModel, artist_id)
        return _to_entity(row) if row is not None else None

    async def get_many(self, ids: list[uuid.UUID]) -> list[Artist]:
        if not ids:
            return []
        rows = (
            (await self._session.execute(select(ArtistModel).where(ArtistModel.id.in_(ids))))
            .scalars()
            .all()
        )
        return [_to_entity(r) for r in rows]

    async def list(self, *, q: str | None, limit: int, offset: int) -> list[Artist]:
        stmt = select(ArtistModel)
        if q:
            stmt = stmt.where(ArtistModel.name.ilike(f"%{q}%"))
        stmt = stmt.order_by(ArtistModel.name).limit(limit).offset(offset)
        rows = (await self._session.execute(stmt)).scalars().all()
        return [_to_entity(r) for r in rows]

    async def count(self, *, q: str | None) -> int:
        stmt = select(func.count()).select_from(ArtistModel)
        if q:
            stmt = stmt.where(ArtistModel.name.ilike(f"%{q}%"))
        return (await self._session.execute(stmt)).scalar_one()

    async def album_count(self, artist_id: uuid.UUID) -> int:
        return (
            await self._session.execute(
                select(func.count())
                .select_from(AlbumModel)
                .where(AlbumModel.artist_id == artist_id)
            )
        ).scalar_one()

    async def track_count(self, artist_id: uuid.UUID) -> int:
        return (
            await self._session.execute(
                select(func.count())
                .select_from(TrackModel)
                .where(TrackModel.artist_id == artist_id)
            )
        ).scalar_one()
