package com.utopiaindustries.qualitychecker.async;

import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Handler;
import android.os.HandlerThread;
import android.os.Looper;

import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

public class ImageProcessor {

    private ExecutorService executorService;
    private Handler backgroundHandler;
    private Handler mainHandler;

    public ImageProcessor() {
        executorService = Executors.newSingleThreadExecutor();
        HandlerThread handlerThread = new HandlerThread("ImageProcessorThread");
        handlerThread.start();
        backgroundHandler = new Handler(handlerThread.getLooper());
        mainHandler = new Handler(Looper.getMainLooper());
    }

    /*public void compressImageFromUriAsync(final Context context, final Uri uri, final int maxSizeKB, final OnImageCompressedListener listener) {
        backgroundHandler.post(() -> {
            byte[] imageData = getBytesFromUri(context, uri);
            if (imageData != null) {
                final byte[] compressedData = compressImageToMaxSize(imageData, maxSizeKB);
                mainHandler.post(() -> listener.onImageCompressed(compressedData));
            } else {
                mainHandler.post(new Runnable() {
                    @Override
                    public void run() {
                        listener.onImageCompressed(null);
                    }
                });
            }
        });
    }*/

    private byte[] getBytesFromUri(Context context, Uri uri) {
        if (uri != null) {
            try {
                InputStream inputStream = context.getContentResolver().openInputStream(uri);
                if (inputStream != null) {
                    ByteArrayOutputStream byteBuffer = new ByteArrayOutputStream();
                    byte[] buffer = new byte[1024];
                    int len;
                    while ((len = inputStream.read(buffer)) != -1) {
                        byteBuffer.write(buffer, 0, len);
                    }
                    inputStream.close();
                    return byteBuffer.toByteArray();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }

    private byte[] compressImageToMaxSize(byte[] imageData, int maxSizeKB) {
        int quality = 100; // Start with the highest quality
        byte[] compressedBytes = compressImage(imageData, quality);
        // Loop to reduce quality until the image is within the max size
        while (compressedBytes.length > maxSizeKB * 1024 && quality > 0) {
            quality -= 5;
            compressedBytes = compressImage(imageData, quality);
        }
        return compressedBytes;
    }

    private byte[] compressImage(byte[] imageData, int quality) {
        if (imageData != null && imageData.length > 0) {
            Bitmap bitmap = BitmapFactory.decodeByteArray(imageData, 0, imageData.length);
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            bitmap.compress(Bitmap.CompressFormat.JPEG, quality, outputStream);
            return outputStream.toByteArray();
        }
        return null;
    }

    public void uriToByteArrayAsync(Context context, Uri uri, int targetSizeInKB, OnImageCompressedListener listener) {
        new Thread(() -> {
            try {
                // Target file size in bytes
                int targetSizeInBytes = targetSizeInKB * 1024;

                // Load the image as a Bitmap without scaling
                Bitmap bitmap;
                try (InputStream inputStream = context.getContentResolver().openInputStream(uri)) {
                    bitmap = BitmapFactory.decodeStream(inputStream);
                }

                if (bitmap == null) {
                    throw new IOException("Failed to decode image from URI.");
                }

                // Initial quality for compression
                int minQuality = 10;
                int maxQuality = 100;
                ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream();
                int quality = maxQuality;

                // Use binary search for quality adjustment to find optimal size faster
                while (minQuality <= maxQuality) {
                    byteArrayOutputStream.reset();
                    bitmap.compress(Bitmap.CompressFormat.JPEG, quality, byteArrayOutputStream);

                    int byteSize = byteArrayOutputStream.size();
                    if (byteSize > targetSizeInBytes) {
                        maxQuality = quality - 5;
                    } else if (byteSize < targetSizeInBytes) {
                        minQuality = quality + 5;
                    } else {
                        break;
                    }
                    quality = (minQuality + maxQuality) / 2;
                }

                // Return compressed byte array
                listener.onCompressed(byteArrayOutputStream.toByteArray());
            } catch (IOException e) {
                listener.onError(e);
            }
        }).start();
    }

    public void shutdown() {
        executorService.shutdown();
    }

    /*public interface OnImageCompressedListener {
        void onImageCompressed(byte[] compressedData);
    }*/

    public interface OnImageCompressedListener {
        void onCompressed(byte[] compressedImage);
        void onError(Exception e);
    }
}
