from sqlalchemy import select

from galaxy.exceptions import RequestParameterInvalidException
from galaxy.security.validate_user_input import (
    validate_email,
    validate_password,
    validate_publicname,
)
from tool_shed.context import ProvidesUserContext
from tool_shed.structured_app import ToolShedApp
from tool_shed.webapp.model import User
from tool_shed_client.schema import (
    CreateUserRequest,
    UserV2 as ApiUser,
)


def index(app: ToolShedApp, deleted: bool) -> list[ApiUser]:
    users: list[ApiUser] = []
    for user in get_users_by_deleted(app.model.context, User, deleted):
        users.append(get_api_user(app, user))
    return users


def create_user(app: ToolShedApp, email: str, username: str, password: str) -> User:
    if username == "repos":
        raise RequestParameterInvalidException("Cannot create a tool shed user with the username repos")
    sa_session = app.model.context
    user = User(email=email)
    user.set_password_cleartext(password)
    user.username = username
    # API was doing this but mypy doesn't think user has an active boolean attribute.
    # if app.config.user_activation_on:
    #    user.active = False
    # else:
    #    user.active = True  # Activation is off, every new user is active by default.
    sa_session.add(user)
    sa_session.commit()
    app.security_agent.create_private_user_role(user)
    return user


def api_create_user(trans: ProvidesUserContext, request: CreateUserRequest) -> ApiUser:
    app = trans.app
    message = _validate(
        trans, email=request.email, password=request.password, confirm=request.password, username=request.username
    )
    if message:
        raise RequestParameterInvalidException(message)
    user = create_user(app, request.email, request.username, request.password)
    return get_api_user(app, user)


def get_api_user(app: ToolShedApp, user: User) -> ApiUser:
    admin = app.config.is_admin_user(user)
    return ApiUser(
        id=app.security.encode_id(user.id),
        username=user.username,
        is_admin=admin,
    )


def _validate(trans: ProvidesUserContext, email: str, password: str, confirm: str, username: str) -> str:
    if username in ["repos"]:
        return f"The term '{username}' is a reserved word in the Tool Shed, so it cannot be used as a public user name."
    message = "\n".join(
        (
            validate_email(trans, email),
            validate_password(trans, password, confirm),
            validate_publicname(trans, username),
        )
    ).rstrip()
    return message


def get_users_by_deleted(session, user_model, deleted):
    stmt = select(user_model).where(user_model.deleted == deleted).order_by(user_model.username)
    return session.scalars(stmt)
