package cc.winboll.studio.powerbell.utils;

import android.content.Context;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.Build;
import android.text.TextUtils;
import cc.winboll.studio.libappbase.LogUtils;
import cc.winboll.studio.powerbell.App;
import java.io.File;
import java.util.Map;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author ZhanGSKen&豆包大模型<zhangsken@qq.com>
 * @Date 2025/12/11 01:57
 * @Describe 单例 Bitmap 缓存工具类（Java 7 兼容）- 极致强制缓存版
 * 功能：内存缓存 Bitmap，支持路径关联缓存、全局获取、缓存清空、SP 持久化最后缓存路径、构造时预加载
 * 特点：1. 单例模式  2. 硬引用唯一缓存（极致强制保持，任何情况不自动回收）  3. 路径-Bitmap 映射  4. 线程安全
 *       5. SP 持久化最后缓存路径  6. 构造时预加载  7. 引用计数防误回收  8. 高压缩比减少OOM风险
 * 核心策略：无论内存如何紧张，强制保持已缓存的Bitmap，通过高压缩比降低单张Bitmap内存占用，永不自动清理
 */
public class BitmapCacheUtils {
    public static final String TAG = "BitmapCacheUtils";
    // 最大图片尺寸（降低至720P，进一步减少内存占用，强制缓存核心策略）
    private static final int MAX_WIDTH = 720;
    private static final int MAX_HEIGHT = 1280;

    // SP 相关常量
    private static final String SP_NAME = "BitmapCacheSP";
    private static final String SP_KEY_LAST_CACHE_PATH = "last_cache_image_path";

    // 单例实例（volatile 保证多线程可见性）
    private static volatile BitmapCacheUtils sInstance;
    // 路径-Bitmap 硬引用缓存（唯一缓存，极致强制保持，任何情况不自动回收）
    private final Map<String, Bitmap> mHardCacheMap;
    // 路径-引用计数 映射（解决多实例共享问题，仅用于统计，不影响缓存生命周期）
    private final Map<String, Integer> mRefCountMap;
    // SP 实例（用于持久化最后缓存路径）
    private final SharedPreferences mSp;

    // 私有构造器（单例模式）
    private BitmapCacheUtils() {
        // 使用ConcurrentHashMap保证线程安全，避免手动同步
        mHardCacheMap = new ConcurrentHashMap<>();
        mRefCountMap = new ConcurrentHashMap<>();
        // 初始化 SP（使用 App 全局上下文，避免内存泄漏）
        mSp = App.getInstance().getSharedPreferences(SP_NAME, Context.MODE_PRIVATE);
        // 构造时自动预加载 SP 中保存的最后一次缓存路径的图片
        preloadLastCachedBitmap();
        // 注册内存状态监听（仅记录日志，不清理缓存）
        registerMemoryStatusListener();
    }

    /**
     * 获取单例实例（双重校验锁，线程安全）
     */
    public static BitmapCacheUtils getInstance() {
        if (sInstance == null) {
            synchronized (BitmapCacheUtils.class) {
                if (sInstance == null) {
                    sInstance = new BitmapCacheUtils();
                }
            }
        }
        return sInstance;
    }

    // ====================================== 新增核心方法：解决App类调用问题 ======================================
    /**
     * 获取当前缓存的Bitmap数量（App类调用专用）
     * @return 缓存的Bitmap数量
     */
    public int getCacheCount() {
        int count = mHardCacheMap.size();
        LogUtils.d(TAG, "getCacheCount: 当前缓存Bitmap数量 - " + count);
        return count;
    }

    /**
     * 获取当前缓存的所有图片路径集合
     * @return 路径集合
     */
    public Set<String> getCachedPaths() {
        return mHardCacheMap.keySet();
    }

    /**
     * 估算当前缓存的总内存占用（单位：字节）
     * @return 总内存占用
     */
    public long getTotalCacheSize() {
        long totalSize = 0;
        for (Bitmap bitmap : mHardCacheMap.values()) {
            if (isBitmapValid(bitmap)) {
                if (Build.VERSION.SDK_INT >= 12) {
                    totalSize += bitmap.getByteCount();
                } else {
                    totalSize += bitmap.getRowBytes() * bitmap.getHeight();
                }
            }
        }
        LogUtils.d(TAG, "getTotalCacheSize: 当前缓存总内存占用 - " + totalSize + " 字节");
        return totalSize;
    }

    // ====================================== 核心接口：缓存操作 ======================================
    /**
     * 补充接口：直接缓存已解码的Bitmap（适配BackgroundView改进需求）
     * @param imagePath 图片绝对路径
     * @param bitmap 已解码的有效Bitmap
     * @return 缓存后的Bitmap / null（参数无效）
     */
    public Bitmap cacheBitmap(String imagePath, Bitmap bitmap) {
        if (TextUtils.isEmpty(imagePath) || !isBitmapValid(bitmap)) {
            LogUtils.e(TAG, "cacheBitmap: 路径或Bitmap无效");
            return null;
        }

        // 极致强制：直接存入硬引用缓存，覆盖旧值（若存在）
        mHardCacheMap.put(imagePath, bitmap);
        // 初始化引用计数为1（若不存在）
        mRefCountMap.putIfAbsent(imagePath, 1);
        // 持久化当前路径到 SP
        saveLastCachePathToSp(imagePath);
        LogUtils.d(TAG, "cacheBitmap: 直接缓存已解码Bitmap成功（极致强制保持） - " + imagePath);
        return bitmap;
    }

    /**
     * 核心接口：根据图片路径缓存 Bitmap 到内存，并持久化路径到 SP
     * @param imagePath 图片绝对路径
     * @return 缓存成功的 Bitmap / null（路径无效/文件不存在/解码失败）
     */
    public Bitmap cacheBitmap(String imagePath) {
        if (TextUtils.isEmpty(imagePath)) {
            LogUtils.e(TAG, "cacheBitmap: 图片路径为空");
            return null;
        }

        File imageFile = new File(imagePath);
        if (!imageFile.exists() || !imageFile.isFile() || imageFile.length() <= 0) {
            LogUtils.e(TAG, "cacheBitmap: 图片文件无效（不存在/非文件/空文件） - " + imagePath);
            return null;
        }

        // 已缓存则直接返回，避免重复加载
        Bitmap hardCacheBitmap = mHardCacheMap.get(imagePath);
        if (isBitmapValid(hardCacheBitmap)) {
            LogUtils.d(TAG, "cacheBitmap: 硬引用缓存命中，引用计数+1 - " + imagePath);
            // 引用计数+1
            increaseRefCount(imagePath);
            // 持久化当前路径到 SP
            saveLastCachePathToSp(imagePath);
            return hardCacheBitmap;
        }

        // 高压缩比加载 Bitmap（强制缓存核心：通过降低分辨率减少单张Bitmap内存占用）
        Bitmap bitmap = decodeCompressedBitmap(imagePath);
        if (bitmap != null) {
            // 极致强制：存入硬引用缓存，永不自动回收
            mHardCacheMap.put(imagePath, bitmap);
            // 初始化引用计数为1
            mRefCountMap.put(imagePath, 1);
            // 持久化当前路径到 SP
            saveLastCachePathToSp(imagePath);
            LogUtils.d(TAG, "cacheBitmap: 图片缓存成功并持久化路径（极致强制保持） - " + imagePath);
        } else {
            LogUtils.e(TAG, "cacheBitmap: 图片解码失败 - " + imagePath);
        }
        return bitmap;
    }

    /**
     * 核心接口：根据路径获取缓存的 Bitmap
     * @param imagePath 图片绝对路径
     * @return 缓存的有效 Bitmap / null（未缓存/已回收）
     */
    public Bitmap getCachedBitmap(String imagePath) {
        if (TextUtils.isEmpty(imagePath)) {
            return null;
        }

        // 仅从硬引用缓存获取，无任何 fallback
        Bitmap hardCacheBitmap = mHardCacheMap.get(imagePath);
        if (isBitmapValid(hardCacheBitmap)) {
            return hardCacheBitmap;
        }

        // 缓存未命中或Bitmap已失效（极致强制策略下，理论上不会出现已回收情况）
        LogUtils.w(TAG, "getCachedBitmap: 缓存未命中或Bitmap已失效 - " + imagePath);
        return null;
    }

    // ====================================== 引用计数管理（仅统计，不影响缓存） ======================================
    /**
     * 新增接口：增加指定路径Bitmap的引用计数
     * @param imagePath 图片绝对路径
     */
    public void increaseRefCount(String imagePath) {
        if (TextUtils.isEmpty(imagePath)) {
            return;
        }
        synchronized (mRefCountMap) {
            Integer count = mRefCountMap.get(imagePath);
            if (count == null) {
                mRefCountMap.put(imagePath, 1);
            } else {
                mRefCountMap.put(imagePath, count + 1);
            }
            LogUtils.d(TAG, "increaseRefCount: " + imagePath + " 引用计数变为 " + mRefCountMap.get(imagePath));
        }
    }

    /**
     * 新增接口：减少指定路径Bitmap的引用计数，计数为0时仅标记不回收（极致强制缓存策略）
     * @param imagePath 图片绝对路径
     */
    public void decreaseRefCount(String imagePath) {
        if (TextUtils.isEmpty(imagePath)) {
            return;
        }
        synchronized (mRefCountMap) {
            Integer count = mRefCountMap.get(imagePath);
            if (count == null || count <= 0) {
                return;
            }

            int newCount = count - 1;
            if (newCount <= 0) {
                // 极致强制缓存策略：引用计数为0时仅移除计数，绝对不回收Bitmap
                mRefCountMap.remove(imagePath);
                LogUtils.d(TAG, "decreaseRefCount: " + imagePath + " 引用计数为0，极致强制保持Bitmap");
            } else {
                mRefCountMap.put(imagePath, newCount);
                LogUtils.d(TAG, "decreaseRefCount: " + imagePath + " 引用计数变为 " + newCount);
            }
        }
    }

    // ====================================== 缓存清理（仅手动调用，永不自动执行） ======================================
    /**
     * 清空所有 Bitmap 缓存（仅手动调用时执行，任何情况不自动执行）
     */
    public void clearAllCache() {
        LogUtils.w(TAG, "clearAllCache: 手动清空所有缓存（极致强制缓存策略下，需谨慎使用）");

        // 清空硬引用缓存并回收Bitmap
        for (Bitmap bitmap : mHardCacheMap.values()) {
            if (isBitmapValid(bitmap)) {
                bitmap.recycle();
            }
        }
        mHardCacheMap.clear();

        // 清空引用计数
        mRefCountMap.clear();

        // 清空 SP 中保存的最后缓存路径
        clearLastCachePathInSp();

        LogUtils.d(TAG, "clearAllCache: 所有 Bitmap 缓存已清空");
    }

    /**
     * 移除指定路径的 Bitmap 缓存（仅手动调用时执行，任何情况不自动执行）
     * @param imagePath 图片绝对路径
     */
    public void removeCachedBitmap(String imagePath) {
        if (TextUtils.isEmpty(imagePath)) {
            return;
        }

        synchronized (mRefCountMap) {
            // 手动移除时才回收Bitmap
            Bitmap hardBitmap = mHardCacheMap.remove(imagePath);
            if (isBitmapValid(hardBitmap)) {
                hardBitmap.recycle();
                LogUtils.d(TAG, "removeCachedBitmap: 手动回收硬引用缓存 - " + imagePath);
            }
            mRefCountMap.remove(imagePath);

            // 若移除的是最后缓存的路径，清空 SP
            String lastPath = getLastCachePathFromSp();
            if (imagePath.equals(lastPath)) {
                clearLastCachePathInSp();
                LogUtils.d(TAG, "removeCachedBitmap: 移除的是最后缓存路径，已清空 SP");
            }
        }
    }

    // ====================================== 内部工具方法 ======================================
    /**
     * 高压缩比解码 Bitmap（极致强制缓存核心：通过降低分辨率+RGB_565减少单张Bitmap内存占用）
     * @param imagePath 图片绝对路径
     * @return 解码后的 Bitmap / null（文件无效/解码失败）
     */
    private Bitmap decodeCompressedBitmap(String imagePath) {
        // 前置校验：确保文件有效
        File imageFile = new File(imagePath);
        if (!imageFile.exists() || !imageFile.isFile() || imageFile.length() <= 0) {
            LogUtils.e(TAG, "decodeCompressedBitmap: 文件无效，跳过解码 - " + imagePath);
            return null;
        }

        BitmapFactory.Options options = new BitmapFactory.Options();
        // 第一步：只获取图片尺寸，不加载像素
        options.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(imagePath, options);

        // 校验尺寸是否有效
        if (options.outWidth <= 0 || options.outHeight <= 0) {
            LogUtils.e(TAG, "decodeCompressedBitmap: 图片尺寸无效 - " + imagePath);
            return null;
        }

        // 计算高压缩比缩放比例（极致强制缓存核心：尽可能降低分辨率）
        int sampleSize = calculateHighCompressSampleSize(options, MAX_WIDTH, MAX_HEIGHT);

        // 第二步：加载高压缩比的 Bitmap
        options.inJustDecodeBounds = false;
        options.inSampleSize = sampleSize;
        options.inPreferredConfig = Bitmap.Config.RGB_565; // 强制使用RGB_565，比ARGB_8888少一半内存
        options.inPurgeable = false; // 关闭可清除标志，极致强制保持内存
        options.inInputShareable = false;
        options.inDither = false; // 关闭抖动，减少内存占用
        options.inScaled = false; // 关闭自动缩放，避免额外内存消耗

        try {
            return BitmapFactory.decodeFile(imagePath, options);
        } catch (OutOfMemoryError e) {
            LogUtils.e(TAG, "decodeCompressedBitmap: OOM异常（已启用高压缩比） - " + imagePath);
            // 极致强制缓存策略：OOM时仅放弃当前解码，绝对不清理已缓存的Bitmap
            return null;
        } catch (Exception e) {
            LogUtils.e(TAG, "decodeCompressedBitmap: 解码异常 - " + imagePath, e);
            return null;
        }
    }

    /**
     * 计算高压缩比缩放比例（极致强制缓存核心：优先保证不超过最大尺寸，尽可能压缩）
     */
    private int calculateHighCompressSampleSize(BitmapFactory.Options options, int maxWidth, int maxHeight) {
        int rawWidth = options.outWidth;
        int rawHeight = options.outHeight;
        int inSampleSize = 1;

        // 高压缩比逻辑：只要超过最大尺寸，就持续放大采样率
        while (rawWidth / inSampleSize > maxWidth || rawHeight / inSampleSize > maxHeight) {
            inSampleSize *= 2;
        }

        // 额外压缩：即使未超过最大尺寸，也强制至少压缩1倍（进一步减少内存占用）
        inSampleSize = Math.max(inSampleSize, 2);

        LogUtils.d(TAG, "calculateHighCompressSampleSize: 高压缩比缩放比例为 " + inSampleSize);
        return inSampleSize;
    }

    /**
     * 工具方法：判断Bitmap是否有效（非空且未被回收）
     */
    private boolean isBitmapValid(Bitmap bitmap) {
        return bitmap != null && !bitmap.isRecycled();
    }

    // ====================================== SP 持久化相关 ======================================
    /**
     * 从 SP 中获取最后一次缓存的图片路径
     * @return 最后缓存的路径 / null（未保存）
     */
    private String getLastCachePathFromSp() {
        return mSp.getString(SP_KEY_LAST_CACHE_PATH, null);
    }

    /**
     * 将当前缓存路径持久化到 SP
     * @param imagePath 图片绝对路径
     */
    private void saveLastCachePathToSp(String imagePath) {
        if (TextUtils.isEmpty(imagePath)) {
            return;
        }
        mSp.edit().putString(SP_KEY_LAST_CACHE_PATH, imagePath).commit(); // Java 7 兼容，使用 commit 而非 apply
        LogUtils.d(TAG, "saveLastCachePathToSp: 持久化最后缓存路径 - " + imagePath);
    }

    /**
     * 清空 SP 中保存的最后缓存路径
     */
    private void clearLastCachePathInSp() {
        mSp.edit().remove(SP_KEY_LAST_CACHE_PATH).commit();
        LogUtils.d(TAG, "clearLastCachePathInSp: SP 中最后缓存路径已清空");
    }

    // ====================================== 预加载相关 ======================================
    /**
     * 构造时预加载 SP 中保存的最后一次缓存路径的图片
     */
    private void preloadLastCachedBitmap() {
        String lastPath = getLastCachePathFromSp();
        if (TextUtils.isEmpty(lastPath)) {
            LogUtils.d(TAG, "preloadLastCachedBitmap: SP 中无保存的缓存路径，跳过预加载");
            return;
        }
        // 调用 cacheBitmap 预加载（内部已做文件校验和缓存判断）
        Bitmap bitmap = cacheBitmap(lastPath);
        if (bitmap != null) {
            LogUtils.d(TAG, "preloadLastCachedBitmap: 预加载 SP 中最后缓存路径成功（极致强制保持） - " + lastPath);
        } else {
            LogUtils.w(TAG, "preloadLastCachedBitmap: 预加载 SP 中最后缓存路径失败，清空无效路径 - " + lastPath);
            // 预加载失败，清空 SP 中无效路径
            clearLastCachePathInSp();
        }
    }

    // ====================================== 内存状态监听（仅记录日志） ======================================
    /**
     * 注册内存状态监听（仅记录日志，不清理缓存，极致强制缓存策略）
     */
    private void registerMemoryStatusListener() {
        if (Build.VERSION.SDK_INT >= 14) {
            App.getInstance().registerComponentCallbacks(new MemoryStatusCallback());
            LogUtils.d(TAG, "registerMemoryStatusListener: 内存状态监听已注册（仅记录日志，不清理缓存）");
        }
    }

    /**
     * 内存状态回调（仅记录日志，不清理缓存，极致强制缓存策略）
     */
    private class MemoryStatusCallback implements android.content.ComponentCallbacks2 {
        @Override
        public void onTrimMemory(int level) {
            // 极致强制缓存策略：内存紧张时仅记录日志，不清理任何缓存
            LogUtils.w(TAG, "onTrimMemory: 内存紧张级别 - " + level + "，极致强制保持所有Bitmap缓存");
            // 记录当前缓存状态
            logCurrentCacheStatus();
        }

        @Override
        public void onLowMemory() {
            // 极致强制缓存策略：低内存时仅记录日志，不清理任何缓存
            LogUtils.w(TAG, "onLowMemory: 系统低内存，极致强制保持所有Bitmap缓存（已启用高压缩比）");
            // 记录当前缓存状态
            logCurrentCacheStatus();
        }

        @Override
        public void onConfigurationChanged(android.content.res.Configuration newConfig) {
            // 配置变化时无需处理
        }
    }

    /**
     * 记录当前缓存状态（用于内存紧张时的调试）
     */
    private void logCurrentCacheStatus() {
        LogUtils.d(TAG, "logCurrentCacheStatus: 缓存数量 - " + getCacheCount() + "，总内存占用 - " + getTotalCacheSize() + " 字节");
        LogUtils.d(TAG, "logCurrentCacheStatus: 缓存路径 - " + getCachedPaths().toString());
    }
}

