package com.ttstd.iconloader;

import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.pm.ActivityInfo;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.drawable.AdaptiveIconDrawable;
import android.graphics.drawable.BitmapDrawable;
import android.graphics.drawable.Drawable;
import android.graphics.drawable.LayerDrawable;
import android.os.Build;
import android.util.Log;

import androidx.collection.LruCache;

import com.jakewharton.disklrucache.DiskLruCache;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class IconCacheManager {
    private static IconCacheManager INSTANCE;

    private static final String TAG = "IconCacheManager";
    private LruCache<String, Drawable> mMemoryCache;
    private DiskLruCache mDiskCache;

    public static void init(Context context) {
        if (context == null) {
            throw new RuntimeException("Context is NULL");
        }
        if (INSTANCE == null) {
            INSTANCE = new IconCacheManager(context);
        }
    }

    public static IconCacheManager getInstance() {
        if (INSTANCE == null) {
            throw new IllegalStateException("You must be init IconCacheManager first");
        }
        return INSTANCE;
    }

    public IconCacheManager(Context context) {
        // 内存缓存（最大8MB）
        int maxMemory = (int) (Runtime.getRuntime().maxMemory() / 1024);
        int cacheSize = maxMemory / 8;
        mMemoryCache = new LruCache<String, Drawable>(cacheSize) {
            @Override
            protected int sizeOf(String key, Drawable icon) {
                if (icon instanceof BitmapDrawable) {
                    return ((BitmapDrawable) icon).getBitmap().getByteCount() / 1024;
                }
                return 1; // 非Bitmap对象按1KB计算
            }
        };

        // 磁盘缓存（50MB）
        File cacheDir = new File(context.getExternalCacheDir(), "icon_cache");
        try {
            mDiskCache = DiskLruCache.open(cacheDir, 1, 1, 50 * 1024 * 1024);
        } catch (Exception e) {
            Log.e(TAG, "IconCacheManager: " + e.getMessage());
        }

        final PackageManager packageManager = context.getPackageManager();
        ExecutorService executor = Executors.newFixedThreadPool(10);
        executor.execute(new Runnable() {
            @Override
            public void run() {
                Intent intent = new Intent(Intent.ACTION_MAIN);
                intent.addCategory(Intent.CATEGORY_LAUNCHER);
                // 查询所有包含CATEGORY_LAUNCHER的Activity
                List<ResolveInfo> resolveInfoList = packageManager.queryIntentActivities(intent, PackageManager.MATCH_ALL);
                for (ResolveInfo resolveInfo : resolveInfoList) {
                    ComponentName componentName = new ComponentName(resolveInfo.activityInfo.packageName, resolveInfo.activityInfo.name);
                    String key = componentName.flattenToShortString();
                    try {
                        ActivityInfo info = packageManager.getActivityInfo(componentName, 0);
                        Drawable rawIcon = info.loadIcon(packageManager);
                        putToMemory(key, rawIcon);
                        putToDisk(key, rawIcon);
                    } catch (Exception e) {
                        Log.e(TAG, "run: " + e.getMessage());
                    }
                }
            }
        });
    }

    public Drawable getFromMemory(String key) {
        return mMemoryCache.get(key);
    }

    public Drawable getFromDisk(String key) {
        String md5 = MD5Util.getMD5(key);
        try {
            DiskLruCache.Snapshot snapshot = mDiskCache.get(md5);
            if (snapshot != null) {
                InputStream in = snapshot.getInputStream(0);
                return Drawable.createFromStream(in, null);
            }
        } catch (IOException e) {
            Log.e(TAG, "getFromDisk Disk read error", e);
        }
        return null;
    }

    public void putToMemory(String key, Drawable icon) {
        mMemoryCache.put(key, icon);
    }

    public void putToDisk(String key, Drawable icon) {
        String md5 = MD5Util.getMD5(key);
        try {
            DiskLruCache.Editor editor = mDiskCache.edit(md5);
            if (icon instanceof BitmapDrawable) {
                Bitmap bitmap = ((BitmapDrawable) icon).getBitmap();
                bitmap.compress(Bitmap.CompressFormat.PNG, 100, editor.newOutputStream(0));
                editor.commit();
            } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                if (icon instanceof AdaptiveIconDrawable) {
                    // 分别获取背景和前景Drawable
//                    Drawable[] layers = new Drawable[2];
//                    layers[0] = ((AdaptiveIconDrawable) icon).getBackground();
//                    layers[1] = ((AdaptiveIconDrawable) icon).getForeground();
//                    LayerDrawable layerDrawable = new LayerDrawable(layers);
//
//                    int width = icon.getIntrinsicWidth();
//                    int height = icon.getIntrinsicHeight();
//
//                    Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
//                    Canvas canvas = new Canvas(bitmap);
//
//                    layerDrawable.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
//                    layerDrawable.draw(canvas);

                    // 创建一个大小与原始Drawable相同的位图
                    Bitmap bitmap = Bitmap.createBitmap(
                            icon.getIntrinsicWidth(),
                            icon.getIntrinsicHeight(),
                            Bitmap.Config.ARGB_8888
                    );
                    Canvas canvas = new Canvas(bitmap);
                    // 关键步骤：设置Drawable的绘制边界
                    icon.setBounds(0, 0, canvas.getWidth(), canvas.getHeight());
                    icon.draw(canvas);

                    bitmap.compress(Bitmap.CompressFormat.PNG, 100, editor.newOutputStream(0));
                    editor.commit();
                }
            }
        } catch (IOException e) {
            Log.e(TAG, "putToDisk Disk write error", e);
        }
    }

    public Drawable getIcon(String key) {
        Drawable memDrawable = getFromMemory(key);
        if (memDrawable != null) {
            Log.i(TAG, "getIcon: fromMemory " + key);
            return memDrawable;
        }
        Drawable diskDrawable = getFromDisk(key);
        if (diskDrawable != null) {
            putToMemory(key, diskDrawable);
            Log.i(TAG, "getIcon: fromDisk " + key);
            return diskDrawable;
        }
        return null;
    }
}