package com.mzh.library.service;

import com.mzh.library.dao.UserDao;
import com.mzh.library.entity.AuthenticatedUser;
import com.mzh.library.entity.Permission;
import com.mzh.library.entity.Role;
import com.mzh.library.entity.User;
import com.mzh.library.exception.DaoException;
import com.mzh.library.service.impl.AuthServiceImpl;
import com.mzh.library.util.PasswordHasher;

import java.util.Optional;
import java.util.logging.Level;
import java.util.logging.Logger;

public final class AuthServiceCheck {
    private static final String REQUIRED_MESSAGE = "请输入用户名和密码。";
    private static final String INVALID_MESSAGE = "用户名或密码不正确。";
    private static final String UNAVAILABLE_MESSAGE =
        "登录服务暂时不可用，请稍后重试。";

    private AuthServiceCheck() {
    }

    public static void main(String[] args) {
        Logger.getLogger(AuthServiceImpl.class.getName()).setLevel(Level.OFF);

        User admin = user(1L, "admin", "System Administrator", Role.ADMINISTRATOR, "correct-password");
        AuthService authService = new AuthServiceImpl(username -> "admin".equals(username)
            ? Optional.of(admin)
            : Optional.empty());

        requireMessage(authService.authenticate("", "correct-password"), REQUIRED_MESSAGE);
        requireMessage(authService.authenticate("admin", ""), REQUIRED_MESSAGE);
        requireMessage(authService.authenticate("missing", "correct-password"), INVALID_MESSAGE);
        requireMessage(authService.authenticate("admin", "wrong-password"), INVALID_MESSAGE);

        AuthenticationResult result = authService.authenticate(" admin ", "correct-password");
        require(result.isAuthenticated(), "valid credentials should authenticate");
        AuthenticatedUser authenticatedUser = result.getUser();
        require(authenticatedUser != null, "authenticated result should include session-safe user");
        require(authenticatedUser.getRole() == Role.ADMINISTRATOR, "admin should resolve to administrator");
        require(authenticatedUser.getPermissionCodes().contains(Permission.MANAGE_USERS.getCode()),
            "administrator should receive manage-users permission code");
        require(authService.hasPermission(authenticatedUser, Permission.VIEW_SYSTEM_LOGS),
            "administrator should have all scaffold permissions");

        AuthService failingService = new AuthServiceImpl(new FailingUserDao());
        requireMessage(failingService.authenticate("admin", "correct-password"), UNAVAILABLE_MESSAGE);
    }

    private static User user(long id, String username, String displayName, Role role, String password) {
        User user = new User();
        user.setId(id);
        user.setUsername(username);
        user.setDisplayName(displayName);
        user.setRole(role);
        user.setPasswordHash(PasswordHasher.hash(password));
        user.setActive(true);
        return user;
    }

    private static void requireMessage(AuthenticationResult result, String message) {
        require(!result.isAuthenticated(), "result should not be authenticated");
        require(message.equals(result.getMessage()), "expected message: " + message);
    }

    private static void require(boolean condition, String message) {
        if (!condition) {
            throw new AssertionError(message);
        }
    }

    private static final class FailingUserDao implements UserDao {
        @Override
        public Optional<User> findActiveByUsername(String username) {
            throw new DaoException("Simulated DAO failure", null);
        }
    }
}
