package com.mosquito.project.service;

import com.mosquito.project.dto.LoginResponse;
import com.mosquito.project.permission.*;
import com.mosquito.project.permission.entity.SysUserEntity;
import com.mosquito.project.permission.entity.SysUserTokenEntity;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.time.Instant;
import java.time.temporal.ChronoUnit;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 认证服务 - 独立登录认证（数据库化版本）
 * 支持用户名密码登录和JWT Token生成
 */
@Service
public class AuthService {

    // 数据库化用户服务
    private final SysUserService sysUserService;
    private final PasswordEncoder passwordEncoder;

    // 数据库仓库，用于获取真实角色和权限
    private final RoleRepository roleRepository;
    private final PermissionRepository permissionRepository;
    private final UserRoleRepository userRoleRepository;
    private final RolePermissionRepository rolePermissionRepository;
    private final PermissionCodeResolver permissionCodeResolver;

    @Autowired
    public AuthService(SysUserService sysUserService,
                      PasswordEncoder passwordEncoder,
                      RoleRepository roleRepository,
                      PermissionRepository permissionRepository,
                      UserRoleRepository userRoleRepository,
                      RolePermissionRepository rolePermissionRepository,
                      PermissionCodeResolver permissionCodeResolver) {
        this.sysUserService = sysUserService;
        this.passwordEncoder = passwordEncoder;
        this.roleRepository = roleRepository;
        this.permissionRepository = permissionRepository;
        this.userRoleRepository = userRoleRepository;
        this.rolePermissionRepository = rolePermissionRepository;
        this.permissionCodeResolver = permissionCodeResolver;
    }

    /**
     * 公开的无参构造函数 - 仅用于测试
     */
    public AuthService() {
        this.sysUserService = null;
        this.passwordEncoder = null;
        this.roleRepository = null;
        this.permissionRepository = null;
        this.userRoleRepository = null;
        this.rolePermissionRepository = null;
        this.permissionCodeResolver = null;
    }

    /**
     * 用户登录
     * 支持BCrypt和SHA-256两种密码验证方式：
     * 1. 新建用户使用BCrypt（通过PasswordEncoder）
     * 2. 旧用户使用SHA-256，验证成功后自动升级到BCrypt
     */
    public LoginResponse login(String username, String password) {
        // 尝试从数据库获取用户
        Optional<SysUserEntity> dbUserOpt = sysUserService.getUserByUsername(username);

        Long userId;
        String displayName;

        if (dbUserOpt.isPresent()) {
            // 数据库用户验证 - 支持BCrypt和SHA-256兼容
            SysUserEntity dbUser = dbUserOpt.get();
            String storedHash = dbUser.getPasswordHash();

            boolean passwordValid = false;

            // 判断存储的哈希类型
            if (storedHash != null && storedHash.startsWith("$2")) {
                // BCrypt格式 - 使用PasswordEncoder验证
                passwordValid = passwordEncoder.matches(password, storedHash);
            } else {
                // SHA-256格式 - 兼容旧用户
                String hashedPassword = hashPassword(password);
                passwordValid = hashedPassword.equals(storedHash);

                // SHA-256验证成功后，自动升级到BCrypt
                if (passwordValid) {
                    String newHash = passwordEncoder.encode(password);
                    sysUserService.updatePasswordHash(dbUser.getId(), newHash);
                }
            }

            if (!passwordValid) {
                throw new IllegalArgumentException("用户名或密码错误");
            }

            ensureUserLoginAllowed(dbUser);
            userId = dbUser.getId();
            displayName = dbUser.getRealName() != null ? dbUser.getRealName() : dbUser.getUsername();
        } else {
            throw new IllegalArgumentException("用户名或密码错误");
        }

        // 从数据库获取用户的真实角色和权限
        List<String> userRoles = getUserRolesFromDatabase(userId);
        Set<String> userPermissions = getUserPermissionsFromDatabase(userId);

        // 生成Token并持久化
        SysUserTokenEntity tokenEntity = sysUserService.createToken(userId, null, null, 24);
        String token = tokenEntity.getToken();
        Instant expiresAt = tokenEntity.getExpiresAt().atZone(java.time.ZoneId.systemDefault()).toInstant();

        // 构建响应
        LoginResponse response = new LoginResponse();
        response.setToken(token);
        response.setTokenType("Bearer");
        response.setExpiresIn(86400L); // 24小时
        response.setUserId(userId);
        response.setUsername(username);
        response.setDisplayName(displayName);
        response.setRoles(userRoles);
        response.setPermissions(new ArrayList<>(userPermissions));

        return response;
    }

    private void ensureUserLoginAllowed(SysUserEntity user) {
        String status = user.getStatus() == null ? "ACTIVE" : user.getStatus();
        if (!"ACTIVE".equalsIgnoreCase(status) || Boolean.TRUE.equals(user.getIsBlacklisted())) {
            throw new IllegalArgumentException("账号已被冻结或拉黑，请联系管理员");
        }
    }

    /**
     * 从数据库获取用户角色
     */
    private List<String> getUserRolesFromDatabase(Long userId) {
        if (roleRepository == null || userRoleRepository == null) {
            return Collections.emptyList();
        }
        try {
            List<Long> roleIds = userRoleRepository.findRoleIdsByUserId(userId);
            if (roleIds == null || roleIds.isEmpty()) {
                return Collections.emptyList();
            }
            return roleIds.stream()
                    .map(roleId -> roleRepository.findById(roleId))
                    .filter(Optional::isPresent)
                    .map(Optional::get)
                    .map(SysRole::getRoleCode)
                    .collect(Collectors.toList());
        } catch (Exception e) {
            return Collections.emptyList();
        }
    }

    /**
     * 从数据库获取用户权限
     */
    private Set<String> getUserPermissionsFromDatabase(Long userId) {
        if (roleRepository == null || userRoleRepository == null ||
            rolePermissionRepository == null || permissionRepository == null) {
            return Collections.emptySet();
        }
        try {
            List<Long> roleIds = userRoleRepository.findRoleIdsByUserId(userId);
            if (roleIds == null || roleIds.isEmpty()) {
                return Collections.emptySet();
            }

            Set<String> permissions = new HashSet<>();
            for (Long roleId : roleIds) {
                List<Long> permissionIds = rolePermissionRepository.findPermissionIdsByRoleId(roleId);
                if (permissionIds != null) {
                    for (Long permId : permissionIds) {
                        permissionRepository.findById(permId)
                                .ifPresent(perm -> permissions.add(perm.getPermissionCode()));
                    }
                }
            }
            return permissions;
        } catch (Exception e) {
            return Collections.emptySet();
        }
    }

    /**
     * 验证Token
     */
    public TokenInfo validateToken(String token) {
        if (token == null || token.isBlank()) {
            return null;
        }

        // 移除Bearer前缀
        if (token.startsWith("Bearer ")) {
            token = token.substring(7);
        }

        // 从数据库验证Token
        Optional<SysUserTokenEntity> tokenOpt = sysUserService.verifyToken(token);
        if (tokenOpt.isEmpty()) {
            return null;
        }

        SysUserTokenEntity tokenEntity = tokenOpt.get();
        return new TokenInfo(tokenEntity.getUserId(), tokenEntity.getExpiresAt().atZone(java.time.ZoneId.systemDefault()).toInstant());
    }

    /**
     * 登出
     */
    public void logout(String token) {
        if (token != null && token.startsWith("Bearer ")) {
            token = token.substring(7);
        }
        sysUserService.deleteToken(token);
    }

    /**
     * 获取用户信息
     */
    public UserInfo getUserById(Long userId) {
        // 优先从数据库获取
        Optional<SysUserEntity> dbUser = sysUserService.getUserById(userId);
        if (dbUser.isPresent()) {
            SysUserEntity user = dbUser.get();
            List<String> roles = getUserRolesFromDatabase(userId);
            List<String> perms = new ArrayList<>(getUserPermissionsFromDatabase(userId));
            return new UserInfo(user.getId(), user.getUsername(), null,
                    user.getRealName() != null ? user.getRealName() : user.getUsername(),
                    user.getDepartmentId(), roles, perms);
        }
        return null;
    }

    private String hashPassword(String password) {
        try {
            MessageDigest digest = MessageDigest.getInstance("SHA-256");
            byte[] hash = digest.digest(password.getBytes(StandardCharsets.UTF_8));
            return bytesToHex(hash);
        } catch (NoSuchAlgorithmException e) {
            throw new RuntimeException("密码加密失败", e);
        }
    }

    private static String bytesToHex(byte[] bytes) {
        StringBuilder sb = new StringBuilder();
        for (byte b : bytes) {
            sb.append(String.format("%02x", b));
        }
        return sb.toString();
    }

    /**
     * 用户信息
     */
    public static class UserInfo {
        public Long id;
        public String username;
        public String passwordHash;
        public String displayName;
        public Long departmentId;
        public List<String> roles;
        public List<String> permissions;

        public UserInfo(Long id, String username, String passwordHash, String displayName,
                       Long departmentId, List<String> roles, List<String> permissions) {
            this.id = id;
            this.username = username;
            this.passwordHash = passwordHash;
            this.displayName = displayName;
            this.departmentId = departmentId;
            this.roles = roles;
            this.permissions = permissions;
        }
    }

    /**
     * Token信息
     */
    public static class TokenInfo {
        public Long userId;
        public Instant expiresAt;

        public TokenInfo(Long userId, Instant expiresAt) {
            this.userId = userId;
            this.expiresAt = expiresAt;
        }
    }
}
