package study.securitybrowser;

import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;

import org.springframework.security.core.userdetails.User;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UserDetailsPasswordService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;
import org.springframework.security.crypto.password.PasswordEncoder;

/** 仅进程内的合成凭据源；不是数据库、生产账号或可复用的默认生产密码。 */
public class SyntheticCredentials implements UserDetailsService, UserDetailsPasswordService {
    private final Map<String, UserDetails> users = new ConcurrentHashMap<>();
    private final Map<String, Integer> upgrades = new ConcurrentHashMap<>();

    public SyntheticCredentials(PasswordEncoder encoder) {
        for (String name : new String[] {"reader", "operator", "session-user", "remember-user"}) {
            users.put(name, User.withUsername(name).password(encoder.encode("lab-password"))
                    .roles(name.equals("operator") ? "ADMIN" : "USER").build());
        }
        users.put("legacy", User.withUsername("legacy").password("{noop}lab-password").roles("USER").build());
    }

    @Override
    public UserDetails loadUserByUsername(String username) {
        UserDetails user = users.get(username);
        if (user == null) {
            throw new UsernameNotFoundException("Synthetic user not found");
        }
        // ProviderManager 默认擦除认证结果的凭据；不能让结果与凭据源共享可擦除的 User 实例。
        return User.withUserDetails(user).build();
    }

    @Override
    public UserDetails updatePassword(UserDetails user, String newPassword) {
        UserDetails replacement = User.withUserDetails(user).password(newPassword).build();
        users.put(user.getUsername(), replacement);
        upgrades.merge(user.getUsername(), 1, Integer::sum);
        return User.withUserDetails(replacement).build();
    }

    public Map<String, Object> legacyMetadata() {
        String stored = users.get("legacy").getPassword();
        return Map.of("encoding", stored.substring(1, stored.indexOf('}')),
                "upgrades", upgrades.getOrDefault("legacy", 0));
    }
}
