package com.test.bijihoudaun.util;

import com.test.bijihoudaun.common.response.R;
import com.test.bijihoudaun.common.response.ResultCode;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;

import java.io.IOException;
import java.lang.management.ManagementFactory;
import java.lang.management.MemoryMXBean;
import java.lang.management.MemoryUsage;
import java.util.concurrent.atomic.AtomicBoolean;

/**
 * 内存保护工具类
 * 监控 JVM 内存使用情况，当内存不足时拒绝请求
 */
@Slf4j
public class MemoryProtector {

    // 内存使用率阈值（百分比），超过此值进入保护模式
    private static final double MEMORY_THRESHOLD_PERCENT = 85.0;
    // 堆内存使用阈值（MB）
    private static final long HEAP_THRESHOLD_MB = 1500;

    // 是否处于保护模式
    private static final AtomicBoolean PROTECTION_MODE = new AtomicBoolean(false);

    // 上次检查时间
    private static volatile long lastCheckTime = 0;
    // 检查间隔（毫秒）
    private static final long CHECK_INTERVAL_MS = 5000;

    /**
     * 检查内存状态，如果内存不足返回 true
     */
    public static boolean isMemoryInsufficient() {
        long now = System.currentTimeMillis();
        // 每 5 秒检查一次，减少性能开销
        if (now - lastCheckTime < CHECK_INTERVAL_MS) {
            return PROTECTION_MODE.get();
        }

        synchronized (MemoryProtector.class) {
            if (now - lastCheckTime < CHECK_INTERVAL_MS) {
                return PROTECTION_MODE.get();
            }
            lastCheckTime = now;

            MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
            MemoryUsage heapUsage = memoryMXBean.getHeapMemoryUsage();

            long usedMB = heapUsage.getUsed() / 1024 / 1024;
            long maxMB = heapUsage.getMax() / 1024 / 1024;
            double usagePercent = maxMB > 0 ? (usedMB * 100.0 / maxMB) : 0;

            boolean shouldProtect = usagePercent > MEMORY_THRESHOLD_PERCENT || usedMB > HEAP_THRESHOLD_MB;

            if (shouldProtect && !PROTECTION_MODE.get()) {
                log.warn("内存不足，进入保护模式 - 使用率: {}%, 已使用: {}MB, 最大: {}MB",
                        String.format("%.2f", usagePercent), usedMB, maxMB);
                PROTECTION_MODE.set(true);
            } else if (!shouldProtect && PROTECTION_MODE.get()) {
                log.info("内存恢复正常，退出保护模式 - 使用率: {}%, 已使用: {}MB",
                        String.format("%.2f", usagePercent), usedMB);
                PROTECTION_MODE.set(false);
            }

            return PROTECTION_MODE.get();
        }
    }

    /**
     * 写入内存不足响应
     */
    public static void writeMemoryInsufficientResponse(HttpServletResponse response) throws IOException {
        response.setContentType("application/json;charset=UTF-8");
        response.setStatus(503);
        response.getWriter().write(
                "{\"code\":" + ResultCode.FAILED.getCode() +
                        ",\"msg\":\"服务器繁忙，请稍后再试\",\"data\":null}"
        );
    }

    /**
     * 获取当前内存状态（用于监控）
     */
    public static MemoryStatus getMemoryStatus() {
        MemoryMXBean memoryMXBean = ManagementFactory.getMemoryMXBean();
        MemoryUsage heapUsage = memoryMXBean.getHeapMemoryUsage();

        MemoryStatus status = new MemoryStatus();
        status.setUsedMB(heapUsage.getUsed() / 1024 / 1024);
        status.setCommittedMB(heapUsage.getCommitted() / 1024 / 1024);
        status.setMaxMB(heapUsage.getMax() / 1024 / 1024);
        status.setUsagePercent(status.getMaxMB() > 0 ?
                (status.getUsedMB() * 100.0 / status.getMaxMB()) : 0);
        status.setProtectionMode(PROTECTION_MODE.get());

        return status;
    }

    /**
     * 内存状态信息
     */
    public static class MemoryStatus {
        private long usedMB;
        private long committedMB;
        private long maxMB;
        private double usagePercent;
        private boolean protectionMode;

        public long getUsedMB() { return usedMB; }
        public void setUsedMB(long usedMB) { this.usedMB = usedMB; }
        public long getCommittedMB() { return committedMB; }
        public void setCommittedMB(long committedMB) { this.committedMB = committedMB; }
        public long getMaxMB() { return maxMB; }
        public void setMaxMB(long maxMB) { this.maxMB = maxMB; }
        public double getUsagePercent() { return usagePercent; }
        public void setUsagePercent(double usagePercent) { this.usagePercent = usagePercent; }
        public boolean isProtectionMode() { return protectionMode; }
        public void setProtectionMode(boolean protectionMode) { this.protectionMode = protectionMode; }
    }
}
