"""Refresh-token repository — adapter implementing
``app.domain.ports.RefreshTokenRepository``.
"""

import datetime as dt
import uuid

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

from app.infrastructure.db.models import RefreshTokenModel


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

    async def add(
        self,
        *,
        jti: uuid.UUID,
        user_id: uuid.UUID,
        token_hash: str,
        expires_at: dt.datetime,
    ) -> None:
        self._session.add(
            RefreshTokenModel(
                jti=jti,
                user_id=user_id,
                token_hash=token_hash,
                expires_at=expires_at,
            )
        )
        await self._session.flush()

    async def is_valid(self, jti: uuid.UUID) -> bool:
        row = (
            await self._session.execute(
                select(RefreshTokenModel).where(RefreshTokenModel.jti == jti)
            )
        ).scalar_one_or_none()
        if row is None or row.revoked_at is not None:
            return False
        return row.expires_at > dt.datetime.now(dt.UTC)

    async def revoke(self, jti: uuid.UUID) -> None:
        await self._session.execute(
            update(RefreshTokenModel)
            .where(RefreshTokenModel.jti == jti, RefreshTokenModel.revoked_at.is_(None))
            .values(revoked_at=dt.datetime.now(dt.UTC))
        )

    async def revoke_all_for_user(self, user_id: uuid.UUID) -> None:
        await self._session.execute(
            update(RefreshTokenModel)
            .where(
                RefreshTokenModel.user_id == user_id,
                RefreshTokenModel.revoked_at.is_(None),
            )
            .values(revoked_at=dt.datetime.now(dt.UTC))
        )
