"""Authentication service."""

from typing import Any

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

from apex.core.security import create_access_token, create_refresh_token, verify_password
from apex.domain.models.user import BaseUser


class AuthService:
    """
    Authentication service for handling login, registration, and token management.

    This is a base implementation. Users should extend this to work with their
    specific User model.
    """

    def __init__(self, session: AsyncSession, user_model: type[BaseUser]):
        """
        Initialize auth service.

        Args:
            session: Database session
            user_model: User model class
        """
        self.session = session
        self.user_model = user_model

    async def authenticate_user(self, email: str, password: str) -> BaseUser | None:
        """
        Authenticate a user by email and password.

        Args:
            email: User email
            password: Plain text password

        Returns:
            User instance if authentication succeeds, None otherwise
        """
        result = await self.session.execute(
            select(self.user_model).where(self.user_model.email == email)
        )
        user = result.scalar_one_or_none()

        if not user:
            return None

        if not verify_password(password, user.password_hash):
            return None

        if not user.is_active:
            return None

        return user

    async def create_tokens(self, user: BaseUser) -> dict[str, Any]:
        """
        Create access and refresh tokens for a user.

        Args:
            user: User instance

        Returns:
            Dictionary with access_token and refresh_token
        """
        token_data = {
            "sub": str(user.id),
            "email": user.email,
            "is_active": user.is_active,
            "is_superuser": user.is_superuser,
            "organization_id": str(user.organization_id) if user.organization_id else None,
        }

        access_token = create_access_token(data=token_data)
        refresh_token = create_refresh_token(data=token_data)

        return {
            "access_token": access_token,
            "refresh_token": refresh_token,
            "token_type": "bearer",
        }

    async def refresh_access_token(self, refresh_token: str) -> dict[str, Any] | None:
        """
        Create a new access token from a refresh token.

        Args:
            refresh_token: Refresh token string

        Returns:
            Dictionary with new access_token or None if refresh token is invalid
        """
        from apex.core.security.jwt import decode_token

        try:
            payload = decode_token(refresh_token)
            if payload.get("type") != "refresh":
                return None

            user_id = payload.get("sub")
            if not user_id:
                return None

            # Verify user still exists and is active
            result = await self.session.execute(
                select(self.user_model).where(self.user_model.id == user_id)
            )
            user = result.scalar_one_or_none()

            if not user or not user.is_active:
                return None

            # Create new access token
            token_data = {
                "sub": str(user.id),
                "email": user.email,
                "is_active": user.is_active,
                "is_superuser": user.is_superuser,
                "organization_id": str(user.organization_id) if user.organization_id else None,
            }

            access_token = create_access_token(data=token_data)

            return {
                "access_token": access_token,
                "token_type": "bearer",
            }

        except Exception:
            return None

