package cn.reghao.tnb.auth.app.db.repository;

import cn.reghao.tnb.auth.api.dto.AccountInfo;
import cn.reghao.tnb.auth.app.db.mapper.UserAccountMapper;
import cn.reghao.tnb.auth.app.db.mapper.UserRoleMapper;
import cn.reghao.tnb.auth.app.db.mapper.UserRegistryMapper;
import cn.reghao.tnb.auth.app.model.po.UserAccount;
import cn.reghao.tnb.auth.app.model.po.UserRole;
import cn.reghao.tnb.auth.app.model.po.UserAuthority;
import cn.reghao.tnb.auth.app.model.po.UserRegistry;
import cn.reghao.tnb.auth.app.model.vo.LoginAccount;
import cn.reghao.tnb.common.auth.AccountRole;
import cn.reghao.tnb.common.util.ConstantId;
import org.springframework.cache.annotation.CacheEvict;
import org.springframework.cache.annotation.Cacheable;
import org.springframework.stereotype.Repository;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.List;
import java.util.Locale;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author reghao
 * @date 2023-06-01 14:12:40
 */
@Repository
public class AccountRepository {
    private final UserAccountMapper userAccountMapper;
    private final UserRegistryMapper userRegistryMapper;
    private final UserRoleMapper userRoleMapper;

    public AccountRepository(UserAccountMapper userAccountMapper, UserRegistryMapper userRegistryMapper,
                             UserRoleMapper userRoleMapper) {
        this.userAccountMapper = userAccountMapper;
        this.userRegistryMapper = userRegistryMapper;
        this.userRoleMapper = userRoleMapper;
    }

    @Transactional(rollbackFor = Exception.class)
    public void saveAccount(UserAccount userAccount) {
        long userId = userAccount.getUserId();
        Set<UserRole> set = userAccount.getAuthorities().stream()
                .map(role -> new UserRole(userId, role.getAuthority()))
                .collect(Collectors.toSet());

        userAccountMapper.save(userAccount);
        userRoleMapper.saveAll(new ArrayList<>(set));
    }

    @CacheEvict(cacheNames = "tnb:account:info", key = "#userId")
    public void updateUserScreenName(long userId, String screenName) {
        userAccountMapper.updateUserScreenName(userId, screenName);
    }

    @CacheEvict(cacheNames = "tnb:account:info", key = "#userId")
    public void updateUserAvatar(long userId, String avatarUrl) {
        userAccountMapper.updateUserAvatar(userId, avatarUrl);
    }

    private void addUserRole(long userId, String role) {
        UserRole userRole = new UserRole(userId, role);
        userRoleMapper.save(userRole);
    }

    @CacheEvict(cacheNames = "tnb:account:registry", key = "'account-registry'")
    public void updateUserRegistry(UserRegistry userRegistry) {
        userRegistryMapper.update(userRegistry);
    }

    public synchronized long getNextUserId() {
        long userId;
        Long maxUserId = userAccountMapper.findMaxUserId();
        if (maxUserId == null) {
            userId = ConstantId.START_USER_ID;
        } else {
            userId = maxUserId + 1;
        }

        return userId;
    }

    @Cacheable(cacheNames = "tnb:account:info", key = "#userId", unless = "#result == null")
    public AccountInfo getAccountInfo(long userId) {
        AccountInfo accountInfo = userAccountMapper.findAccountInfo(userId);
        return accountInfo;
    }

    public LoginAccount getLoginAccount(long userId) {
        AccountInfo accountInfo = userAccountMapper.findAccountInfo(userId);
        List<String> roles = getUserRoles(userId).stream()
                .map(role -> role.replace("ROLE_", "").toLowerCase(Locale.ROOT))
                .collect(Collectors.toList());
        return new LoginAccount(accountInfo, roles);
    }

    /**
     * 获取某个 user 拥有的所有 role
     *
     * @param
     * @return
     * @date 2025-10-17 11:30:05
     */
    public Set<String> getUserRoles(long userId) {
        return userRoleMapper.findRolesByUserId(userId).stream()
                .map(UserRole::getName)
                .collect(Collectors.toSet());
    }

    public List<Long> getRoleUsers(String role) {
        for (AccountRole accountRole : AccountRole.values()) {
            String role1 = accountRole.getValue();
        }

        List<Long> userIds = userRoleMapper.findUserIdsByRole(role);
        return userIds;
    }

    @Cacheable(cacheNames = "tnb:account:registry", key = "'account-registry'", unless = "#result == null")
    public UserRegistry getUserRegistry() {
        List<UserRegistry> list = userRegistryMapper.findAll();
        if (list.isEmpty()) {
            userRegistryMapper.save(new UserRegistry());
        }
        return userRegistryMapper.findAll().get(0);
    }

    public long getUserIdByUsername(String username) {
        return userAccountMapper.findUserIdByUsername(username);
    }

    public List<AccountInfo> getAccountInfos(List<Long> userIds) {
        return userAccountMapper.findAccountInfos(userIds);
    }

    public AccountInfo getAccountInfoByMobile(String mobile) {
        AccountInfo accountInfo = userAccountMapper.findAccountInfoByMobile(mobile);
        return accountInfo;
    }

    public AccountInfo getAccountInfoByUsername(String username) {
        AccountInfo accountInfo = userAccountMapper.findAccountInfoByUsername(username);
        return accountInfo;
    }

    public UserAccount getUserAccountByUserId(long userId) {
        UserAccount userAccount = userAccountMapper.findByUserId(userId);
        return userAccount != null ? setAccountAuthorities(userAccount) : null;
    }

    public UserAccount getUserAccountByUsername(String username) {
        UserAccount userAccount = userAccountMapper.findByUsername(username);
        return userAccount != null ? setAccountAuthorities(userAccount) : null;
    }

    public UserAccount getUserAccountByEmail(String email) {
        UserAccount userAccount = userAccountMapper.findByEmail(email);
        return userAccount != null ? setAccountAuthorities(userAccount) : null;
    }

    public UserAccount getUserAccountByMobile(String mobile) {
        UserAccount userAccount = userAccountMapper.findByMobile(mobile);
        return userAccount != null ? setAccountAuthorities(userAccount) : null;
    }

    private UserAccount setAccountAuthorities(UserAccount userAccount) {
        Set<UserAuthority> set = userRoleMapper.findRolesByUserId(userAccount.getUserId()).stream()
                .map(userRole -> new UserAuthority(userRole.getName()))
                .collect(Collectors.toSet());
        userAccount.setAuthorities(set);
        return userAccount;
    }
}
