"""Auth service — login, token refresh, and current-user resolution."""

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

from app.core.security import (
    create_access_token,
    create_refresh_token,
    verify_password,
    verify_token,
)
from app.models.role import Role, UserSpbuAssignment
from app.models.user import User
from app.repositories import system_repository, user_repository
from app.schemas.auth import TokenResponse, UserResponse


async def login(db: AsyncSession, identifier: str, password: str) -> TokenResponse:
    """Authenticate a user by email or username and return access + refresh tokens.

    Raises ValueError for invalid credentials, inactive accounts, or maintenance mode.
    """
    user = await user_repository.get_by_email(db, identifier)
    if not user:
        user = await user_repository.get_by_username(db, identifier)
    if not user or not verify_password(password, user.password_hash):
        raise ValueError("Email/username atau password salah")
    if not user.is_active:
        raise ValueError("Akun tidak aktif")

    if not user.is_superadmin:
        # Block login when maintenance mode is active
        maintenance = await system_repository.is_maintenance_mode(db)
        if maintenance:
            raise ValueError("__MAINTENANCE__")

        # Block login if none of the user's roles allow web access
        result = await db.execute(
            select(Role)
            .join(UserSpbuAssignment, UserSpbuAssignment.role_id == Role.id)
            .where(UserSpbuAssignment.user_id == user.id, Role.can_login_web.is_(True))
            .limit(1)
        )
        if not result.scalar_one_or_none():
            raise ValueError("Akses web tidak diizinkan untuk role Anda. Hubungi admin.")

    token_data = {"sub": str(user.id), "is_superadmin": user.is_superadmin}
    access_token = create_access_token(token_data)
    refresh_token = create_refresh_token(token_data)
    return TokenResponse(access_token=access_token, refresh_token=refresh_token)


async def refresh_access_token(db: AsyncSession, refresh_token: str) -> str:
    """Exchange a valid refresh token for a new access token."""
    payload = verify_token(refresh_token, token_type="refresh")
    if not payload:
        raise ValueError("Refresh token tidak valid")
    user_id = int(payload["sub"])
    user = await user_repository.get_by_id(db, user_id)
    if not user or not user.is_active:
        raise ValueError("User tidak ditemukan atau tidak aktif")
    token_data = {"sub": str(user.id), "is_superadmin": user.is_superadmin}
    return create_access_token(token_data)


async def get_current_user(db: AsyncSession, token: str) -> User:
    """Resolve and return the active user from an access token."""
    payload = verify_token(token, token_type="access")
    if not payload:
        raise ValueError("Token tidak valid")
    user_id = int(payload["sub"])
    user = await user_repository.get_by_id(db, user_id)
    if not user or not user.is_active:
        raise ValueError("User tidak ditemukan atau tidak aktif")
    return user


def user_to_response(user: User) -> UserResponse:
    """Convert a User ORM model to a UserResponse schema."""
    return UserResponse(
        id=user.id,
        name=user.name,
        email=user.email,
        is_superadmin=user.is_superadmin,
        is_active=user.is_active,
    )
