package com.xyw.console.auth;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.xyw.console.asset.entity.SystemUserEntity;
import com.xyw.console.asset.mapper.SystemUserMapper;
import com.xyw.console.auth.dto.PasswordResetRequest;
import com.xyw.console.auth.dto.SystemUserCreateRequest;
import com.xyw.console.auth.dto.SystemUserResponse;
import com.xyw.console.auth.dto.SystemUserUpdateRequest;
import java.time.LocalDateTime;
import java.util.List;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Service;

@Service
public class SystemUserAdminService {
  private final SystemUserMapper users; private final PagePermissionService permissions; private final PasswordEncoder encoder;
  /** 代码作用（白话）：接收账号表、页面权限和密码哈希依赖；关联文件：SystemUserAdminController.java、SystemUserMapper.java。关联逻辑（调用链/数据流）：管理接口 -> 本服务 -> 用户表/权限 JSON/BCrypt。 */
  public SystemUserAdminService(SystemUserMapper users, PagePermissionService permissions, PasswordEncoder encoder) { this.users = users; this.permissions = permissions; this.encoder = encoder; }
  /** 代码作用（白话）：查询管理者可见的非开发者账号，任何响应都不返回哈希；关联文件：SystemUserAdminController.java、UserPermissionView.js。关联逻辑（调用链/数据流）：账号页面 -> GET users -> as_system_user(role != DEVELOPER) -> 列表。 */
  public List<SystemUserResponse> listVisibleUsers() { assertAdministrator(); return users.selectList(new LambdaQueryWrapper<SystemUserEntity>().ne(SystemUserEntity::getRoleCode, "DEVELOPER").eq(SystemUserEntity::getDeleteTime, 0L).orderByDesc(SystemUserEntity::getId)).stream().map(this::responseOf).toList(); }
  /** 代码作用（白话）：按当前创建者的角色边界新增非开发者账号；关联文件：SystemUserCreateRequest.java、SystemUserAdminController.java。关联逻辑（调用链/数据流）：创建表单 -> 创建者校验 -> 密码/禁用规则 -> as_system_user。 */
  public SystemUserResponse createUser(SystemUserCreateRequest request) { String actor = currentRole(); assertCreatableRole(actor, request.roleCode()); if (users.selectCount(new LambdaQueryWrapper<SystemUserEntity>().eq(SystemUserEntity::getUsername, request.username()).eq(SystemUserEntity::getDeleteTime, 0L)) > 0) throw new IllegalArgumentException("用户名已存在"); SystemUserEntity user = new SystemUserEntity(); user.setUsername(request.username()); user.setRoleCode(request.roleCode()); user.setPagePermissions(permissions.validatePermissions(request.pagePermissions())); user.setDeleteTime(0L); user.setCreateTime(LocalDateTime.now()); user.setUpdateTime(LocalDateTime.now()); user.setAuthVersion(1); if ("SUPER_ADMIN".equals(actor)) { user.setStatus("DISABLED"); user.setPasswordHash(null); } else { requireValidPassword(request.password(), request.username()); user.setStatus("ACTIVE"); user.setPasswordHash(encoder.encode(request.password())); } users.insert(user); return responseOf(user); }
  /** 代码作用（白话）：更新非开发者账号的角色、启停和逐页权限，禁止绕过 Jeddy；关联文件：SystemUserUpdateRequest.java、PagePermissionService.java。关联逻辑（调用链/数据流）：编辑面板 -> 角色边界 -> 用户表更新 -> 下次请求按新权限判定。 */
  public SystemUserResponse updateUser(Long id, SystemUserUpdateRequest request) { String actor = currentRole(); assertCreatableRole(actor, request.roleCode()); SystemUserEntity user = findManageableUser(id); validateRequestedStatus(request.status(), user); String normalizedPermissions = permissions.validatePermissions(request.pagePermissions()); boolean authorizationChanged = authorizationStateChanged(user, request, normalizedPermissions); user.setRoleCode(request.roleCode()); user.setStatus(request.status()); user.setPagePermissions(normalizedPermissions); if (authorizationChanged) user.setAuthVersion(nextAuthVersion(user.getAuthVersion())); user.setUpdateTime(LocalDateTime.now()); users.updateById(user); return responseOf(user); }
  /** Plain purpose: decide whether an account edit changes authorization facts embedded in its existing login token. Related files: PagePermissionService.java, AuthTokenFilter.java. Flow: saved account/request -> normalized authorization comparison -> auth-version increment or session retention. */
  private boolean authorizationStateChanged(SystemUserEntity user, SystemUserUpdateRequest request, String normalizedPermissions) { return !java.util.Objects.equals(user.getRoleCode(), request.roleCode()) || !java.util.Objects.equals(user.getStatus(), request.status()) || !java.util.Objects.equals(permissions.normalizeStoredPermissions(user.getPagePermissions()), normalizedPermissions); }
  /** Plain purpose: return the next usable login-ticket version even for a historical row with a null version. Related files: SystemUserEntity.java, AuthTokenFilter.java. Flow: authorization change -> incremented authVersion -> old JWT rejected on next request. */
  private int nextAuthVersion(Integer currentVersion) { return (currentVersion == null ? 1 : currentVersion) + 1; }
  /** Plain purpose: reject invalid status transitions before changing an account entity. Related files: SystemUserUpdateRequest.java, SystemUserAdminService.java. Flow: update request -> status validation -> safe entity update or readable failure. */
  private void validateRequestedStatus(String status, SystemUserEntity user) { if (!("ACTIVE".equals(status) || "DISABLED".equals(status))) throw new IllegalArgumentException("账号状态无效"); if ("ACTIVE".equals(status) && user.getPasswordHash() == null) throw new IllegalArgumentException("请由开发者先设置密码后再启用账号"); }
  /** 代码作用（白话）：仅允许开发者为非开发者账号设置密码，并交给数据库触发器记录时间及失效旧会话；关联文件：PasswordResetRequest.java、V1__system_user_auth_permissions.sql。关联逻辑（调用链/数据流）：开发者表单 -> BCrypt hash -> UPDATE password_hash -> trigger(auth_version)。 */
  public void resetPassword(Long id, PasswordResetRequest request) { if (!"DEVELOPER".equals(currentRole())) throw new AccessDeniedException("只有开发者可以修改密码"); SystemUserEntity user = findManageableUser(id); requireValidPassword(request.password(), user.getUsername()); user.setPasswordHash(encoder.encode(request.password())); user.setUpdateTime(LocalDateTime.now()); users.updateById(user); }
  /** 代码作用（白话）：确认当前会话属于开发者或超级管理员；关联文件：AuthTokenFilter.java、SystemUserAdminController.java。关联逻辑（调用链/数据流）：Cookie 身份 -> SecurityContext -> 管理接口准入。 */
  private void assertAdministrator() { if (!permissions.isAdministrator(currentRole())) throw new AccessDeniedException("没有账号管理权限"); }
  /** 代码作用（白话）：读取过滤器已经核验过的当前角色；关联文件：AuthPrincipal.java、AuthTokenFilter.java。关联逻辑（调用链/数据流）：JWT -> SecurityContext principal -> 创建/修改边界。 */
  private String currentRole() { Object principal = SecurityContextHolder.getContext().getAuthentication() == null ? null : SecurityContextHolder.getContext().getAuthentication().getPrincipal(); if (!(principal instanceof AuthPrincipal user)) throw new AccessDeniedException("没有账号管理权限"); return user.roleCode(); }
  /** 代码作用（白话）：按角色边界阻止创建开发者以及普通角色创建账号；关联文件：SystemUserCreateRequest.java、SystemUserUpdateRequest.java。关联逻辑（调用链/数据流）：当前角色 + 目标角色 -> 允许或 403。 */
  private void assertCreatableRole(String actor, String roleCode) { if ("DEVELOPER".equals(roleCode)) throw new AccessDeniedException("开发者账号仅允许固定账号 Jeddy"); if (!("SUPER_ADMIN".equals(roleCode) || "FINANCE".equals(roleCode) || "HR".equals(roleCode) || "OPERATIONS".equals(roleCode))) throw new IllegalArgumentException("角色无效"); if ("DEVELOPER".equals(actor) || "SUPER_ADMIN".equals(actor)) return; throw new AccessDeniedException("没有账号管理权限"); }
  /** 代码作用（白话）：按固定查询条件取得可管理账号，避免 Jeddy 通过 URL 或接口细节泄露；关联文件：SystemUserMapper.java、SystemUserResponse.java。关联逻辑（调用链/数据流）：账号 id -> 非 DEVELOPER 查询 -> 编辑/重置。 */
  private SystemUserEntity findManageableUser(Long id) { SystemUserEntity user = users.selectOne(new LambdaQueryWrapper<SystemUserEntity>().eq(SystemUserEntity::getId, id).ne(SystemUserEntity::getRoleCode, "DEVELOPER").eq(SystemUserEntity::getDeleteTime, 0L)); if (user == null) throw new IllegalArgumentException("账号不存在"); return user; }
  /** 代码作用（白话）：验证密码长度和用户名相似度，避免弱密码直接进入数据库；关联文件：PasswordResetRequest.java、SystemUserCreateRequest.java。关联逻辑（调用链/数据流）：密码输入 -> 规则校验 -> BCrypt 哈希。 */
  private void requireValidPassword(String password, String username) { if (password == null || password.length() < 12 || password.length() > 72 || password.toLowerCase().contains(username.toLowerCase())) throw new IllegalArgumentException("密码需为 12-72 位且不能包含用户名"); }
  /** 代码作用（白话）：将实体转为安全响应，并统一展开固定管理员的有效权限；关联文件：SystemUserResponse.java、PagePermissionService.java。关联逻辑（调用链/数据流）：实体 -> 权限计算 -> 前端列表。 */
  private SystemUserResponse responseOf(SystemUserEntity user) { return new SystemUserResponse(user.getId(), user.getUsername(), user.getRoleCode(), user.getStatus(), permissions.effectivePermissions(user), user.getPasswordUpdatedAt()); }
}
