package com.mosquito.project.service;

import com.mosquito.project.permission.PermissionCodeResolver;
import com.mosquito.project.permission.PermissionRepository;
import com.mosquito.project.permission.RolePermissionRepository;
import com.mosquito.project.permission.RoleRepository;
import com.mosquito.project.permission.SysUserService;
import com.mosquito.project.permission.UserRoleRepository;
import com.mosquito.project.permission.entity.SysUserEntity;
import com.mosquito.project.permission.entity.SysUserTokenEntity;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.springframework.security.crypto.password.PasswordEncoder;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Optional;

import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.*;

@DisplayName("AuthService 测试")
class AuthServiceTest {

    private SysUserService sysUserService;
    private PasswordEncoder passwordEncoder;
    private RoleRepository roleRepository;
    private PermissionRepository permissionRepository;
    private UserRoleRepository userRoleRepository;
    private RolePermissionRepository rolePermissionRepository;
    private PermissionCodeResolver permissionCodeResolver;
    private AuthService authService;

    @BeforeEach
    void setUp() {
        sysUserService = mock(SysUserService.class);
        passwordEncoder = mock(PasswordEncoder.class);
        roleRepository = mock(RoleRepository.class);
        permissionRepository = mock(PermissionRepository.class);
        userRoleRepository = mock(UserRoleRepository.class);
        rolePermissionRepository = mock(RolePermissionRepository.class);
        permissionCodeResolver = mock(PermissionCodeResolver.class);
        authService = new AuthService(sysUserService, passwordEncoder, roleRepository, permissionRepository,
            userRoleRepository, rolePermissionRepository, permissionCodeResolver);
    }

    @Test
    @DisplayName("冻结用户不能登录")
    void frozenUserCannotLogin() {
        SysUserEntity user = activeUser();
        user.setStatus("FROZEN");
        user.setPasswordHash("$2a$10$hashed");

        when(sysUserService.getUserByUsername("frozen_user")).thenReturn(Optional.of(user));
        when(passwordEncoder.matches("password", "$2a$10$hashed")).thenReturn(true);

        assertThatThrownBy(() -> authService.login("frozen_user", "password"))
            .isInstanceOf(IllegalArgumentException.class)
            .hasMessageContaining("账号已被冻结或拉黑");
    }

    @Test
    @DisplayName("黑名单用户不能登录")
    void blacklistedUserCannotLogin() {
        SysUserEntity user = activeUser();
        user.setIsBlacklisted(true);
        user.setPasswordHash("$2a$10$hashed");

        when(sysUserService.getUserByUsername("blocked_user")).thenReturn(Optional.of(user));
        when(passwordEncoder.matches("password", "$2a$10$hashed")).thenReturn(true);

        assertThatThrownBy(() -> authService.login("blocked_user", "password"))
            .isInstanceOf(IllegalArgumentException.class)
            .hasMessageContaining("账号已被冻结或拉黑");
    }

    @Test
    @DisplayName("旧SHA-256密码登录后应升级并持久化")
    void legacyShaPasswordShouldBeUpgradedAndPersisted() {
        SysUserEntity user = activeUser();
        user.setPasswordHash(sha256("password"));

        SysUserTokenEntity tokenEntity = new SysUserTokenEntity();
        tokenEntity.setUserId(101L);
        tokenEntity.setToken("token-abc");
        tokenEntity.setExpiresAt(LocalDateTime.now().plusHours(24));

        when(sysUserService.getUserByUsername("legacy_user")).thenReturn(Optional.of(user));
        when(passwordEncoder.encode("password")).thenReturn("$2a$10$newhash");
        when(sysUserService.createToken(eq(101L), any(), any(), eq(24))).thenReturn(tokenEntity);
        when(userRoleRepository.findRoleIdsByUserId(101L)).thenReturn(List.of());

        authService.login("legacy_user", "password");

        verify(sysUserService).updatePasswordHash(101L, "$2a$10$newhash");
        verify(sysUserService).createToken(eq(101L), any(), any(), eq(24));
    }

    @Test
    @DisplayName("默认禁用Demo账号回退")
    void demoFallbackShouldBeDisabledByDefault() {
        when(sysUserService.getUserByUsername("admin")).thenReturn(Optional.empty());
        assertThatThrownBy(() -> authService.login("admin", "admin"))
            .isInstanceOf(IllegalArgumentException.class)
            .hasMessageContaining("用户名或密码错误");
    }

    private SysUserEntity activeUser() {
        SysUserEntity user = new SysUserEntity();
        user.setId(101L);
        user.setUsername("user_101");
        user.setRealName("测试用户");
        user.setStatus("ACTIVE");
        user.setIsBlacklisted(false);
        return user;
    }

    private String sha256(String value) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hash = digest.digest(value.getBytes(StandardCharsets.UTF_8));
            StringBuilder sb = new StringBuilder();
            for (byte b : hash) {
                sb.append(String.format("%02x", b));
            }
            return sb.toString();
        } catch (Exception e) {
            throw new RuntimeException(e);
        }
    }
}
