package com.zioinfo.mall.admin;

import com.zioinfo.mall.admin.dto.UserDto;
import com.zioinfo.mall.admin.mapper.AdminUserMapper;
import com.zioinfo.mall.auth.MallUser;
import lombok.RequiredArgsConstructor;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

import java.util.List;
import java.util.Set;

/**
 * 관리자 사용자 관리 서비스 (ADMIN 전용).
 *
 * <p>보안: 응답은 항상 {@link UserDto} 로 변환하여 password_hash 노출을 차단한다.
 */
@Service
@RequiredArgsConstructor
public class AdminUserService {

    private static final Set<String> VALID_ROLES = Set.of("ADMIN", "MANAGER", "USER");

    private final AdminUserMapper mapper;
    private final PasswordEncoder passwordEncoder;
    private final AuditService auditService;

    public List<UserDto> list() {
        return mapper.findAll().stream().map(UserDto::from).toList();
    }

    public UserDto create(String username, String password, String role, String displayName) {
        if (username == null || username.isBlank()) {
            throw new IllegalArgumentException("ERR-USR-400: username 필수");
        }
        if (password == null || password.isBlank()) {
            throw new IllegalArgumentException("ERR-USR-400: password 필수");
        }
        String resolvedRole = normalizeRole(role);
        if (mapper.countByUsername(username) > 0) {
            throw new RuntimeException("ERR-USR-409: 이미 존재하는 username");
        }
        MallUser user = new MallUser();
        user.setUsername(username);
        user.setPasswordHash(passwordEncoder.encode(password));
        user.setRole(resolvedRole);
        user.setDisplayName(displayName == null || displayName.isBlank() ? username : displayName);
        user.setActive(true);
        mapper.insert(user);
        auditService.log("USER_CREATE", username, "role=" + resolvedRole);
        return UserDto.from(user);
    }

    public UserDto updateRole(Long id, String role) {
        MallUser user = require(id);
        String newRole = normalizeRole(role);
        if ("ADMIN".equals(user.getRole()) && !"ADMIN".equals(newRole)
                && user.isActive() && mapper.countAdmins() <= 1) {
            throw new RuntimeException("ERR-USR-423: 마지막 ADMIN 계정의 역할은 변경할 수 없습니다");
        }
        mapper.updateRole(id, newRole);
        auditService.log("USER_ROLE_CHANGE", user.getUsername(), user.getRole() + " -> " + newRole);
        return UserDto.from(require(id));
    }

    public UserDto updateActive(Long id, boolean active) {
        MallUser user = require(id);
        if (!active && "ADMIN".equals(user.getRole()) && user.isActive() && mapper.countAdmins() <= 1) {
            throw new RuntimeException("ERR-USR-423: 마지막 ADMIN 계정은 비활성화할 수 없습니다");
        }
        mapper.updateActive(id, active);
        auditService.log("USER_ACTIVE_TOGGLE", user.getUsername(), "active=" + active);
        return UserDto.from(require(id));
    }

    public UserDto resetPassword(Long id, String newPassword) {
        if (newPassword == null || newPassword.isBlank()) {
            throw new IllegalArgumentException("ERR-USR-400: password 필수");
        }
        MallUser user = require(id);
        mapper.updatePassword(id, passwordEncoder.encode(newPassword));
        auditService.log("USER_PASSWORD_RESET", user.getUsername(), "password reset");
        return UserDto.from(user);
    }

    public void delete(Long id, String currentUsername) {
        MallUser user = require(id);
        if (user.getUsername().equals(currentUsername)) {
            throw new RuntimeException("ERR-USR-423: 자기 자신은 삭제할 수 없습니다");
        }
        if ("ADMIN".equals(user.getRole()) && user.isActive() && mapper.countAdmins() <= 1) {
            throw new RuntimeException("ERR-USR-423: 마지막 ADMIN 계정은 삭제할 수 없습니다");
        }
        mapper.deleteById(id);
        auditService.log("USER_DELETE", user.getUsername(), "role=" + user.getRole());
    }

    private MallUser require(Long id) {
        MallUser user = mapper.findById(id);
        if (user == null) {
            throw new RuntimeException("ERR-USR-404: 사용자를 찾을 수 없습니다");
        }
        return user;
    }

    private String normalizeRole(String role) {
        if (role == null || role.isBlank()) {
            return "USER";
        }
        String upper = role.trim().toUpperCase();
        if (!VALID_ROLES.contains(upper)) {
            throw new IllegalArgumentException("ERR-USR-400: 유효하지 않은 role (ADMIN/MANAGER/USER)");
        }
        return upper;
    }
}
