package com.bonait.bnframework.common.glide.transform;

import android.graphics.Bitmap;
import android.graphics.BitmapShader;
import android.graphics.Canvas;
import android.graphics.Matrix;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;

import androidx.annotation.NonNull;

import com.bumptech.glide.load.engine.bitmap_recycle.BitmapPool;
import com.bumptech.glide.load.resource.bitmap.TransformationUtils;
import com.bumptech.glide.util.Synthetic;

import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;

/**
 * @author Nov
 * @date 23.7.11
 */
public class TransformationFitXYUtils {
    private static final Lock BITMAP_DRAWABLE_LOCK =
            new NoLock();

    @NonNull
    private static Bitmap.Config getNonNullConfig(@NonNull Bitmap bitmap) {
        return bitmap.getConfig() != null ? bitmap.getConfig() : Bitmap.Config.ARGB_8888;
    }

    private static void applyMatrix(
            @NonNull Bitmap inBitmap, @NonNull Bitmap targetBitmap, Matrix matrix) {
        BITMAP_DRAWABLE_LOCK.lock();
        try {
            Canvas canvas = new Canvas(targetBitmap);
            canvas.drawBitmap(inBitmap, matrix, DEFAULT_PAINT);
            clear(canvas);
        } finally {
            BITMAP_DRAWABLE_LOCK.unlock();
        }
    }

    public static final int PAINT_FLAGS = Paint.DITHER_FLAG | Paint.FILTER_BITMAP_FLAG;
    private static final Paint DEFAULT_PAINT = new Paint(PAINT_FLAGS);

    private static final class NoLock implements Lock {

        @Synthetic
        NoLock() {
        }

        @Override
        public void lock() {
            // do nothing
        }

        @Override
        public void lockInterruptibly() throws InterruptedException {
            // do nothing
        }

        @Override
        public boolean tryLock() {
            return true;
        }

        @Override
        public boolean tryLock(long time, @NonNull TimeUnit unit) throws InterruptedException {
            return true;
        }

        @Override
        public void unlock() {
            // do nothing
        }

        @NonNull
        @Override
        public Condition newCondition() {
            throw new UnsupportedOperationException("Should not be called");
        }
    }

    private static void clear(Canvas canvas) {
        canvas.setBitmap(null);
    }


    public static Bitmap fitXY(
            @NonNull BitmapPool pool, @NonNull Bitmap inBitmap, int width, int height) {

        if (inBitmap.getWidth() == width && inBitmap.getHeight() == height) {
            return inBitmap;
        }
        final float widthPercentage = width / (float) inBitmap.getWidth();
        final float heightPercentage = height / (float) inBitmap.getHeight();
        int targetWidth = (int) (widthPercentage * inBitmap.getWidth());
        int targetHeight = (int) (heightPercentage * inBitmap.getHeight());

        Bitmap.Config config = getNonNullConfig(inBitmap);
        Bitmap toReuse = pool.get(targetWidth, targetHeight, config);
        TransformationUtils.setAlpha(inBitmap, toReuse);
        Matrix matrix = new Matrix();
        matrix.setScale(widthPercentage, heightPercentage);
        applyMatrix(inBitmap, toReuse, matrix);
        return toReuse;
    }

    public static Bitmap roundCrop(BitmapPool pool,
                                    Bitmap source,
                                    float topLeft,
                                    float topRight,
                                    float bottomRight,
                                    float bottomLeft) {
        if (source == null) return null;

        Bitmap result = pool.get(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
        if (result == null) {
            result = Bitmap.createBitmap(source.getWidth(), source.getHeight(), Bitmap.Config.ARGB_8888);
        }
        BitmapShader shader =
                new BitmapShader(source, BitmapShader.TileMode.CLAMP, BitmapShader.TileMode.CLAMP);

        Paint paint = new Paint();
        paint.setShader(shader);
        paint.setAntiAlias(true);
        RectF rect = new RectF(0f, 0f, source.getWidth(), source.getHeight());
        BITMAP_DRAWABLE_LOCK.lock();
        try {
            Canvas canvas = new Canvas(result);
            Path path = new Path();
            path.addRoundRect(
                    rect,
                    new float[]{
                            topLeft,
                            topLeft,
                            topRight,
                            topRight,
                            bottomRight,
                            bottomRight,
                            bottomLeft,
                            bottomLeft
                    },
                    Path.Direction.CW);
            canvas.drawPath(path, paint);
            clear(canvas);
        } finally {
            BITMAP_DRAWABLE_LOCK.unlock();
        }
        return result;
    }
}
