package com.mosquito.project.permission;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Map;

/**
 * 权限审计服务
 * 负责记录权限变更操作到审计日志
 */
@Service
public class PermissionAuditService {

    private static final Logger log = LoggerFactory.getLogger(PermissionAuditService.class);

    private final PermissionAuditRepository auditRepository;
    private final ObjectMapper objectMapper;

    // 操作类型常量
    public static final String OP_ASSIGN_PERMISSION = "ASSIGN_PERMISSION";
    public static final String OP_REVOKE_PERMISSION = "REVOKE_PERMISSION";
    public static final String OP_ASSIGN_ROLE = "ASSIGN_ROLE";
    public static final String OP_REVOKE_ROLE = "REVOKE_ROLE";
    public static final String OP_UPDATE_DATA_SCOPE = "UPDATE_DATA_SCOPE";
    public static final String OP_ASSIGN_ROLE_PERMISSION = "ASSIGN_ROLE_PERMISSION";

    // 目标类型常量
    public static final String TARGET_USER = "USER";
    public static final String TARGET_ROLE = "ROLE";
    public static final String TARGET_PERMISSION = "PERMISSION";

    public PermissionAuditService(PermissionAuditRepository auditRepository, ObjectMapper objectMapper) {
        this.auditRepository = auditRepository;
        this.objectMapper = objectMapper;
    }

    /**
     * 记录权限分配
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logAssignPermission(Long operatorId, Long targetUserId, Long permissionId,
                                    String permissionCode, String ipAddress, String reason) {
        try {
            SysPermissionAudit audit = new SysPermissionAudit();
            audit.setOperatorId(operatorId);
            audit.setOperationType(OP_ASSIGN_PERMISSION);
            audit.setTargetType(TARGET_USER);
            audit.setTargetId(targetUserId);
            audit.setIpAddress(ipAddress);
            audit.setReason(reason);

            Map<String, Object> detail = Map.of(
                "permissionId", permissionId != null ? permissionId : "",
                "permissionCode", permissionCode != null ? permissionCode : "",
                "targetUserId", targetUserId
            );
            audit.setChangeDetail(toJson(detail));

            auditRepository.save(audit);
            log.info("权限分配审计记录已保存: operator={}, targetUser={}, permission={}",
                operatorId, targetUserId, permissionCode);
        } catch (Exception e) {
            log.error("保存权限分配审计记录失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 记录权限撤销
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logRevokePermission(Long operatorId, Long targetUserId, Long permissionId,
                                    String permissionCode, String ipAddress, String reason) {
        try {
            SysPermissionAudit audit = new SysPermissionAudit();
            audit.setOperatorId(operatorId);
            audit.setOperationType(OP_REVOKE_PERMISSION);
            audit.setTargetType(TARGET_USER);
            audit.setTargetId(targetUserId);
            audit.setIpAddress(ipAddress);
            audit.setReason(reason);

            Map<String, Object> detail = Map.of(
                "permissionId", permissionId != null ? permissionId : "",
                "permissionCode", permissionCode != null ? permissionCode : "",
                "targetUserId", targetUserId
            );
            audit.setChangeDetail(toJson(detail));

            auditRepository.save(audit);
            log.info("权限撤销审计记录已保存: operator={}, targetUser={}, permission={}",
                operatorId, targetUserId, permissionCode);
        } catch (Exception e) {
            log.error("保存权限撤销审计记录失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 记录角色分配
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logAssignRole(Long operatorId, Long targetUserId, Long roleId,
                              String roleCode, String ipAddress, String reason) {
        try {
            SysPermissionAudit audit = new SysPermissionAudit();
            audit.setOperatorId(operatorId);
            audit.setOperationType(OP_ASSIGN_ROLE);
            audit.setTargetType(TARGET_USER);
            audit.setTargetId(targetUserId);
            audit.setIpAddress(ipAddress);
            audit.setReason(reason);

            Map<String, Object> detail = Map.of(
                "roleId", roleId != null ? roleId : "",
                "roleCode", roleCode != null ? roleCode : "",
                "targetUserId", targetUserId
            );
            audit.setChangeDetail(toJson(detail));

            auditRepository.save(audit);
            log.info("角色分配审计记录已保存: operator={}, targetUser={}, role={}",
                operatorId, targetUserId, roleCode);
        } catch (Exception e) {
            log.error("保存角色分配审计记录失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 记录角色撤销
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logRevokeRole(Long operatorId, Long targetUserId, Long roleId,
                              String roleCode, String ipAddress, String reason) {
        try {
            SysPermissionAudit audit = new SysPermissionAudit();
            audit.setOperatorId(operatorId);
            audit.setOperationType(OP_REVOKE_ROLE);
            audit.setTargetType(TARGET_USER);
            audit.setTargetId(targetUserId);
            audit.setIpAddress(ipAddress);
            audit.setReason(reason);

            Map<String, Object> detail = Map.of(
                "roleId", roleId != null ? roleId : "",
                "roleCode", roleCode != null ? roleCode : "",
                "targetUserId", targetUserId
            );
            audit.setChangeDetail(toJson(detail));

            auditRepository.save(audit);
            log.info("角色撤销审计记录已保存: operator={}, targetUser={}, role={}",
                operatorId, targetUserId, roleCode);
        } catch (Exception e) {
            log.error("保存角色撤销审计记录失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 记录数据权限变更
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logUpdateDataScope(Long operatorId, Long targetUserId, String oldScope,
                                   String newScope, Long departmentId, String ipAddress, String reason) {
        try {
            SysPermissionAudit audit = new SysPermissionAudit();
            audit.setOperatorId(operatorId);
            audit.setOperationType(OP_UPDATE_DATA_SCOPE);
            audit.setTargetType(TARGET_USER);
            audit.setTargetId(targetUserId);
            audit.setIpAddress(ipAddress);
            audit.setReason(reason);

            Map<String, Object> detail = Map.of(
                "oldDataScope", oldScope != null ? oldScope : "",
                "newDataScope", newScope != null ? newScope : "",
                "departmentId", departmentId != null ? departmentId : "",
                "targetUserId", targetUserId
            );
            audit.setChangeDetail(toJson(detail));

            auditRepository.save(audit);
            log.info("数据权限变更审计记录已保存: operator={}, targetUser={}, {}->{}",
                operatorId, targetUserId, oldScope, newScope);
        } catch (Exception e) {
            log.error("保存数据权限变更审计记录失败: {}", e.getMessage(), e);
        }
    }

    /**
     * 记录角色权限分配
     */
    @Transactional(propagation = Propagation.REQUIRES_NEW)
    public void logAssignRolePermission(Long operatorId, Long roleId, Long permissionId,
                                         String roleCode, String permissionCode, String ipAddress, String reason) {
        try {
            SysPermissionAudit audit = new SysPermissionAudit();
            audit.setOperatorId(operatorId);
            audit.setOperationType(OP_ASSIGN_ROLE_PERMISSION);
            audit.setTargetType(TARGET_ROLE);
            audit.setTargetId(roleId);
            audit.setIpAddress(ipAddress);
            audit.setReason(reason);

            Map<String, Object> detail = Map.of(
                "roleId", roleId != null ? roleId : "",
                "roleCode", roleCode != null ? roleCode : "",
                "permissionId", permissionId != null ? permissionId : "",
                "permissionCode", permissionCode != null ? permissionCode : ""
            );
            audit.setChangeDetail(toJson(detail));

            auditRepository.save(audit);
            log.info("角色权限分配审计记录已保存: operator={}, role={}, permission={}",
                operatorId, roleCode, permissionCode);
        } catch (Exception e) {
            log.error("保存角色权限分配审计记录失败: {}", e.getMessage(), e);
        }
    }

    private String toJson(Object obj) {
        try {
            return objectMapper.writeValueAsString(obj);
        } catch (Exception e) {
            return "{}";
        }
    }
}
