"""
Repository for working with the :class:`~server.modules.rate.repository.models.Vote` model.
Only the “write‑only” operation – adding a vote – is required in the current
application logic.  The repository keeps the database interaction
encapsulated and provides an asynchronous API that can be used by the
service layer (or any other consumer).

The implementation uses the same pattern that is already present in the
``CharactersRepository`` – an async session manager from
``server.infra.db.AsyncDB`` and an interface that makes unit‑testing
straightforward.
"""

from abc import ABCMeta, abstractmethod

from server.infra.db import AsyncDB
from server.modules.rate.repository import models


# --------------------------------------------------------------------------- #
# 1️⃣  Base interface
# --------------------------------------------------------------------------- #
class AVoteRepository(metaclass=ABCMeta):
    """
    Abstract repository that declares the contract for working with votes.
    At the moment only one operation is required – inserting a new vote.
    """

    @abstractmethod
    async def add_vote(self, vote: models.Vote) -> None:
        """Persist ``vote`` into the database."""
        raise NotImplementedError


# --------------------------------------------------------------------------- #
# 2️⃣  Concrete PostgreSQL implementation
# --------------------------------------------------------------------------- #
class PGVoteRepository(AVoteRepository):
    """
    PostgreSQL implementation of :class:`AVoteRepository`.

    The repository is intentionally *minimal* – only an ``add_vote`` method
    is exposed.  The rest of the CRUD operations are expected to be added
    later if/when the business logic grows.
    """

    _db: AsyncDB

    def __init__(self, db: AsyncDB):
        self._db = db

    # --------------------------------------------------------------------- #
    # 2.1  Add a vote
    # --------------------------------------------------------------------- #
    async def add_vote(self, vote: models.Vote) -> None:
        """
        Insert ``vote`` into the ``votes`` table.

        Parameters
        ----------
        vote:
            Instance of :class:`~server.modules.rate.repository.models.Vote`
            containing all necessary fields (``id``, ``attachment_id``,
            ``beerd_id``, ``rate`` and ``created_at``).  The instance
            is a *mapped* dataclass, therefore SQLAlchemy can persist it
            directly.

        Notes
        -----
        * No explicit caching – the operation mutates the database and
          should never be served from a cache.
        * The method is deliberately ``async`` because it uses
          ``AsyncDB.async_session``.
        """
        async with self._db.async_session() as session:
            # We use the *instance* directly – SQLAlchemy will handle the
            # mapping for us.  ``insert`` could also be used, but the
            # instance‑based approach keeps type‑checking and IDE
            # auto‑completion in sync with the dataclass.
            session.add(vote)
            await session.commit()
