package live.videosdk.rnwebrtc;

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Matrix;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.util.Base64;
import android.util.Log;

import org.webrtc.VideoFrame;

import java.io.ByteArrayOutputStream;
import java.nio.ByteBuffer;

public class BitmapVideoFrameConversion {
    private static byte[] createNV21Data(VideoFrame.I420Buffer i420Buffer) {
        final int width = i420Buffer.getWidth();
        final int height = i420Buffer.getHeight();
        final int chromaStride = width;
        final int chromaWidth = (width + 1) / 2;
        final int chromaHeight = (height + 1) / 2;
        final int ySize = width * height;
        final ByteBuffer nv21Buffer = ByteBuffer.allocateDirect(ySize + chromaStride * chromaHeight);
        @SuppressWarnings("ByteBufferBackingArray") final byte[] nv21Data = nv21Buffer.array();
        for (int y = 0; y < height; ++y) {
            for (int x = 0; x < width; ++x) {
                final byte yValue = i420Buffer.getDataY().get(y * i420Buffer.getStrideY() + x);
                nv21Data[y * width + x] = yValue;
            }
        }
        for (int y = 0; y < chromaHeight; ++y) {
            for (int x = 0; x < chromaWidth; ++x) {
                final byte uValue = i420Buffer.getDataU().get(y * i420Buffer.getStrideU() + x);
                final byte vValue = i420Buffer.getDataV().get(y * i420Buffer.getStrideV() + x);
                nv21Data[ySize + y * chromaStride + 2 * x + 0] = vValue;
                nv21Data[ySize + y * chromaStride + 2 * x + 1] = uValue;
            }
        }
        return nv21Data;
    }

    /** Convert a byte array to a direct ByteBuffer. */
    private static ByteBuffer toByteBuffer(int[] array) {
        final ByteBuffer buffer = ByteBuffer.allocateDirect(array.length);
        buffer.put(toByteArray(array));
        buffer.rewind();
        return buffer;
    }


    /**
     * Convert an int array to a byte array and make sure the values are within the range [0, 255].
     */
    private static byte[] toByteArray(int[] array) {
        final byte[] res = new byte[array.length];
        for (int i = 0; i < array.length; ++i) {
            final int value = array[i];
            res[i] = (byte) value;
        }
        return res;
    }
    String i420toBitmapConversion(VideoFrame.I420Buffer i420Buffer,String facingMode,int imageHeight,int imageWidth) {
        final int width = i420Buffer.getWidth();
        final int height = i420Buffer.getHeight();
        //convert to nv21
        byte[] nv21Data = createNV21Data(i420Buffer);

        //converting the NV21 data to jpg
        YuvImage yuvImage = new YuvImage(nv21Data, ImageFormat.NV21,width,height,null);

        ByteArrayOutputStream out = new ByteArrayOutputStream();
        yuvImage.compressToJpeg(new Rect(0, 0, width, height), 100, out);
        byte[] imageBytes = out.toByteArray();
        
        Bitmap bitMap = BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);

        float scaleFactor = (float) 1.0;
        int degrees = facingMode.equals("environment") ? 90 : 270; //rotation degree


        // Matrix matrix = new Matrix();
        // matrix.postRotate(degrees);
        // bitMap = Bitmap.createBitmap(bitMap, 0, 0, bitMap.getWidth(), bitMap.getHeight(), matrix, true);

        // if(imageWidth == 0)
        // {
        //     imageWidth = imageHeight;
        //     scaleFactor = (float) imageHeight / (float) bitMap.getWidth();
        //     Log.d("VideoSDK","scaleFactor" + scaleFactor);
        //     imageWidth = (int) (bitMap.getHeight() * scaleFactor);
        //     Log.d("VideoSDK","imageWidth " + imageWidth);
        // }
        // if(imageHeight == 0)
        // {
        //     imageHeight = imageWidth;
        //     scaleFactor = (float) imageHeight / (float) bitMap.getHeight();
        //     Log.d("VideoSDK","scaleFactor" + scaleFactor);
        //     imageHeight = (int) (bitMap.getWidth() * scaleFactor);
        //     Log.d("VideoSDK","imageHeight " + imageHeight);
        // }

        if(imageWidth == 0)
        {
            scaleFactor = (float) imageHeight / (float) bitMap.getHeight();
            imageWidth = (int) (bitMap.getWidth() * scaleFactor);
        }
        if(imageHeight == 0)
        {
            scaleFactor = (float) imageWidth / (float) bitMap.getWidth();
            imageHeight = (int) (bitMap.getHeight() * scaleFactor);
        }

        try{      
            bitMap = resizeBitmap(bitMap,imageWidth,imageHeight,degrees);
        }catch(Exception e){
            Log.e("videosdk","Error on resizeBitMap "+ e.getMessage());
        }
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        bitMap.compress(Bitmap.CompressFormat.JPEG, 100, outputStream);
        byte[] byteArray = outputStream.toByteArray();
        return Base64.encodeToString(byteArray, Base64.DEFAULT);
    }


    // private static Bitmap resizeBitmap(final Bitmap input, int destWidth, int destHeight, int rotation ) throws OutOfMemoryError 
    // {
    //     int dstWidth = destWidth;
    //     int dstHeight = destHeight;
    //     final int srcWidth = input.getWidth();
    //     final int srcHeight = input.getHeight();

    //     if ( rotation == 90 || rotation == 270 ) {
    //         dstWidth = destHeight;
    //         dstHeight = destWidth;
    //     }

    //     Bitmap output;
    //     Matrix matrix = new Matrix();
    //     matrix.postScale( (float) dstWidth / srcWidth, (float) dstHeight / srcHeight );
    //     matrix.postRotate( rotation );
    //     output = Bitmap.createBitmap(input, 0, 0, srcWidth, srcHeight, matrix, true);
    //     return output; 
    // }

     private static Bitmap resizeBitmap(final Bitmap input, int destWidth, int destHeight, int rotation ) throws OutOfMemoryError 
    {

        int width = input.getWidth();
        int height = input.getHeight();
        
        int dstWidth = destWidth;
        int dstHeight = destHeight;

        if ( rotation == 90 || rotation == 270 ) {
            dstWidth = destHeight;
            dstHeight = destWidth;
        }

        float scaleWidth = ((float) dstWidth) / width;
        float scaleHeight = ((float) dstHeight) / height;

       // create a matrix for the manipulation
        Matrix matrix = new Matrix();
        // resize the bit map
        matrix.postScale(scaleWidth, scaleHeight);
        // rotate the Bitmap
        matrix.postRotate(rotation);
        // recreate the new Bitmap
        Bitmap output = Bitmap.createBitmap(input, 0, 0,
                          width, height, matrix, true);
        return output; 
    }
}

