package com.xyw.console.auth;

import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.xyw.console.asset.entity.SystemUserEntity;
import java.util.LinkedHashMap;
import java.util.Map;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.stereotype.Service;

@Service
public class PagePermissionService {
  public static final String OVERVIEW = "overview";
  public static final String DOMAIN = "domain";
  public static final String WECOM = "reference-wecom";
  public static final String PHONE = "phone-assets";
  public static final String ALERTS = "alerts";
  private static final Map<String, String> PAGES = Map.of(OVERVIEW, "总览", DOMAIN, "域名资料", WECOM, "企微资料", PHONE, "手机号资产", ALERTS, "提醒中心");
  private final ObjectMapper objectMapper;

  /** 代码作用（白话）：接收 JSON 工具以读取数据库权限映射；关联文件：SystemUserEntity.java。关联逻辑（调用链/数据流）：page_permissions JSON -> 权限 Map -> Controller 判定。 */
  public PagePermissionService(ObjectMapper objectMapper) { this.objectMapper = objectMapper; }

  /** 代码作用（白话）：生成当前账号的有效五页权限，开发者和超级管理员固定全编辑；关联文件：AuthService.java、App.js。关联逻辑（调用链/数据流）：用户表 -> 有效权限 -> /api/auth/me -> 菜单和路由。 */
  public Map<String, String> effectivePermissions(SystemUserEntity user) {
    Map<String, String> result = new LinkedHashMap<>();
    PAGES.keySet().forEach(key -> result.put(key, isAdministrator(user.getRoleCode()) ? "EDIT" : "NONE"));
    if (!isAdministrator(user.getRoleCode()) && user.getPagePermissions() != null) try { Map<String, String> saved = objectMapper.readValue(user.getPagePermissions(), new TypeReference<>() {}); saved.forEach((key, value) -> { if (PAGES.containsKey(key) && validLevel(value)) result.put(key, value); }); } catch (Exception ignored) { }
    return result;
  }

  /** 代码作用（白话）：校验权限面板提交内容，只接受已注册页面和三档权限；关联文件：SystemUserAdminService.java。关联逻辑（调用链/数据流）：表单 Map -> 校验/标准化 -> JSON 入库。 */
  public String validatePermissions(Map<String, String> input) {
    Map<String, String> normalized = new LinkedHashMap<>();
    if (input != null) input.forEach((key, value) -> { if (!PAGES.containsKey(key) || !validLevel(value)) throw new IllegalArgumentException("页面权限配置无效"); normalized.put(key, value); });
    try { return objectMapper.writeValueAsString(normalized); } catch (Exception error) { throw new IllegalStateException("页面权限无法保存", error); }
  }

  /** Plain purpose: convert a saved permission JSON value into the same validated form used for a new account request. Related files: SystemUserAdminService.java, SystemUserEntity.java. Flow: stored permission JSON -> normalized map -> role-change comparison -> auth-version decision. */
  public String normalizeStoredPermissions(String storedPermissions) {
    if (storedPermissions == null || storedPermissions.isBlank()) return validatePermissions(Map.of());
    try { return validatePermissions(objectMapper.readValue(storedPermissions, new TypeReference<>() {})); }
    catch (Exception ignored) { return validatePermissions(Map.of()); }
  }

  /** 代码作用（白话）：在资产接口执行服务端最低权限检查；关联文件：PhoneAssetController.java、WecomAccountController.java。关联逻辑（调用链/数据流）：Controller -> 当前认证身份 -> READ/EDIT 决定 403 或继续业务服务。 */
  public void require(String pageKey, String minimum) {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    if (authentication == null || !(authentication.getPrincipal() instanceof AuthPrincipal principal)) throw new AccessDeniedException("没有页面权限");
    String permission = authentication.getDetails() instanceof Map<?, ?> map ? String.valueOf(map.get(pageKey)) : "NONE";
    if (!("EDIT".equals(permission) || ("READ".equals(permission) && "READ".equals(minimum)))) throw new AccessDeniedException("没有页面权限");
  }

  /** Plain purpose: stop non-administrators before an administrator-only controller reaches business data. Related files: DeviceAssetController.java, AuthTokenFilter.java. Flow: authenticated token principal -> administrator role check -> device controller or 403 response. */
  public void requireAdministrator() {
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication();
    if (authentication == null || !(authentication.getPrincipal() instanceof AuthPrincipal principal) || !isAdministrator(principal.roleCode())) throw new AccessDeniedException("没有权限");
  }

  /** 代码作用（白话）：判断角色是否固定拥有全部编辑权限；关联文件：SystemUserAdminService.java。关联逻辑（调用链/数据流）：role_code -> 全量权限或逐页权限。 */
  public boolean isAdministrator(String roleCode) { return "DEVELOPER".equals(roleCode) || "SUPER_ADMIN".equals(roleCode); }
  /** 代码作用（白话）：限制权限值为三档，避免未知值意外放行；关联文件：UserPermissionView.js。关联逻辑（调用链/数据流）：前端单选值 -> 后端验证 -> 持久化。 */
  private boolean validLevel(String value) { return "NONE".equals(value) || "READ".equals(value) || "EDIT".equals(value); }
}
