from __future__ import annotations

from datetime import datetime

from sqlalchemy import delete, select
from sqlalchemy.orm import Session

from supply_infra.db.models.auth_session import AuthSession
from supply_infra.db.models.auth_user import AuthUser


class AuthRepository:
    """Persistence operations for local users and server-side sessions."""

    def __init__(self, session: Session) -> None:
        self.session = session

    def get_user(self, user_id: int) -> AuthUser | None:
        return self.session.get(AuthUser, user_id)

    def get_user_by_username(self, username: str) -> AuthUser | None:
        stmt = select(AuthUser).where(AuthUser.username == username)
        return self.session.scalar(stmt)

    def list_users(self) -> list[AuthUser]:
        stmt = select(AuthUser).order_by(AuthUser.created_at.asc(), AuthUser.id.asc())
        return list(self.session.scalars(stmt).all())

    def create_user(
        self,
        *,
        username: str,
        password_hash: str,
        display_name: str,
        role: str,
        status: str = "active",
    ) -> AuthUser:
        user = AuthUser(
            username=username,
            password_hash=password_hash,
            display_name=display_name,
            role=role,
            status=status,
        )
        self.session.add(user)
        self.session.flush()
        return user

    def delete_user(self, user: AuthUser) -> None:
        self.session.delete(user)
        self.session.flush()

    def create_session(
        self,
        *,
        token_hash: str,
        user_id: int,
        expires_at: datetime,
        ip_address: str | None,
        user_agent: str | None,
    ) -> AuthSession:
        auth_session = AuthSession(
            token_hash=token_hash,
            user_id=user_id,
            expires_at=expires_at,
            ip_address=ip_address,
            user_agent=user_agent,
        )
        self.session.add(auth_session)
        self.session.flush()
        return auth_session

    def get_active_session(
        self,
        *,
        token_hash: str,
        now: datetime,
    ) -> AuthUser | None:
        stmt = (
            select(AuthUser)
            .select_from(AuthSession)
            .join(AuthUser, AuthUser.id == AuthSession.user_id)
            .where(
                AuthSession.token_hash == token_hash,
                AuthSession.expires_at > now,
                AuthUser.status == "active",
            )
        )
        return self.session.scalar(stmt)

    def delete_session_by_hash(self, token_hash: str) -> None:
        self.session.execute(
            delete(AuthSession).where(AuthSession.token_hash == token_hash)
        )

    def delete_user_sessions(self, user_id: int) -> None:
        self.session.execute(
            delete(AuthSession).where(AuthSession.user_id == user_id)
        )

    def delete_expired_sessions(self, now: datetime) -> None:
        self.session.execute(
            delete(AuthSession).where(AuthSession.expires_at <= now)
        )
