package com.zioinfo.mes.admin;

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

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

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

    private static final Set<String> VALID_ROLES = Set.of("SUPERADMIN", "MANAGER", "WORKER", "VIEWER");

    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 displayName, String role) {
        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");
        }
        MesUser user = new MesUser();
        user.setUsername(username);
        user.setPasswordHash(passwordEncoder.encode(password));
        user.setDisplayName(displayName == null || displayName.isBlank() ? username : displayName);
        user.setRole(resolvedRole);
        user.setActive(true);
        mapper.insert(user);
        auditService.log("USER_CREATE", username, "role=" + resolvedRole);
        return UserDto.from(user);
    }

    public UserDto updateRole(Long id, String role) {
        MesUser user = require(id);
        String newRole = normalizeRole(role);
        if ("SUPERADMIN".equals(user.getRole()) && !"SUPERADMIN".equals(newRole)
                && user.isActive() && mapper.countSuperAdmins() <= 1) {
            throw new RuntimeException("ERR-USR-423: 마지막 SUPERADMIN 계정의 역할은 변경할 수 없습니다");
        }
        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) {
        MesUser user = require(id);
        if (!active && "SUPERADMIN".equals(user.getRole()) && user.isActive()
                && mapper.countSuperAdmins() <= 1) {
            throw new RuntimeException("ERR-USR-423: 마지막 SUPERADMIN 계정은 비활성화할 수 없습니다");
        }
        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 필수");
        }
        MesUser user = require(id);
        mapper.updatePassword(id, passwordEncoder.encode(newPassword));
        auditService.log("USER_PASSWORD_RESET", user.getUsername(), "password reset");
        return UserDto.from(user);
    }

    /**
     * 관리자 OTP 초기화(SUPERADMIN). 대상 사용자의 OTP 시크릿을 폐기하고 등록을 해제한다.
     * 사용자는 다음 로그인 시 OTP_SETUP(재등록) 플로우를 탄다. 시크릿은 응답/로그에 노출하지 않는다.
     */
    public UserDto resetOtp(Long id) {
        MesUser user = require(id);
        mapper.clearOtp(id);
        auditService.log("USER_OTP_RESET", user.getUsername(), "OTP 초기화(다음 로그인 재등록)");
        return UserDto.from(user);
    }

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

    private MesUser require(Long id) {
        MesUser 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 "VIEWER";
        }
        String upper = role.trim().toUpperCase();
        if (!VALID_ROLES.contains(upper)) {
            throw new IllegalArgumentException("ERR-USR-400: 유효하지 않은 role (SUPERADMIN/MANAGER/WORKER/VIEWER)");
        }
        return upper;
    }
}
