package com.jiangdg.uvc;


import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.SurfaceTexture;
import android.graphics.YuvImage;
import android.hardware.usb.UsbDevice;
import android.opengl.GLES11Ext;
import android.os.Handler;
import android.os.Vibrator;
import android.view.Surface;

import com.elvishew.xlog.XLog;
import com.jiangdg.usb.USBMonitor;
import com.jiangdg.utils.HandlerThreadHandler;
import com.wmdigit.camera.listener.OnImageAnalyzeListener;
import com.wmdigit.common.model.SimpleUsbDevice;
import com.wmdigit.common.utils.NV21ToBitmap;
import com.wmdigit.common.utils.YuvToRgbConverter;
import com.wmdigit.data.mmkv.repository.CameraLocalRepository;

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

/**
 * @author dizi
 */
public class USBCameraHelper  {
    private static final String TAG = USBCameraHelper.class.getSimpleName();
    private static USBCameraHelper instance;
    private final Object mSync = new Object();
    private final Object mSyncFrame = new Object();
    private Context mContext;
    private USBMonitor mUSBMonitor;
    private UVCCamera mUVCCamera;
    private Vibrator mVibraotor = null;
    private SurfaceTexture mSurfaceTexture;
    private Surface mPreviewSurface;
    private NV21ToBitmap nv21ToBitmap;
    private Handler mWorkerHandler;
    private long mWorkerThreadID = -1;
    private volatile byte[] frame;
    private long latestAttachTimestamp = 0L;
    private long latestDetachTimestamp = 0L;
//    private OnCameraOpenListener onCameraOpenListener;
    boolean isFirstFrame = false;

    /**
     * 图片分析回调
     */
    private OnImageAnalyzeListener onImageAnalyzeListener;

    public void setOnImageAnalyzeListener(OnImageAnalyzeListener onImageAnalyzeListener) {
        this.onImageAnalyzeListener = onImageAnalyzeListener;
    }

    private IFrameCallback iFrameCallback = new IFrameCallback() {

        int count = 0;
        int frameInterval = 3;

        @Override
        public void onFrame(ByteBuffer buffer) {
            synchronized (mSyncFrame) {
                count ++;
                int len = buffer.capacity();
                if (frame != null){
                    frame = null;
                }
                frame = new byte[len];
                buffer.get(frame);
                if (count % frameInterval == 0){
                    count = 0;
                    if (onImageAnalyzeListener != null){
//                        onImageAnalyzeListener.onAnalyzed(encodeYuvToJpeg(frame, 640, 480, ImageFormat.NV21));
                        onImageAnalyzeListener.onAnalyzed(nv21ToBitmap.nv21ToBitmap(frame, 640, 480));
//                        onImageAnalyzeListener.onAnalyzed(BitmapFactory.decodeByteArray(frame, 0, frame.length));
                    }
                }
            }
        }
    };

    private Bitmap encodeYuvToJpeg(byte[] yuvData, int width, int height, int format){
        try {
            // 将YUV数据转换为Bitmap
            YuvImage yuvImage = new YuvImage(yuvData, format, width, height, null);
            ByteArrayOutputStream out = new ByteArrayOutputStream();
            yuvImage.compressToJpeg(new Rect(0, 0, width, height), 75, out);
            byte[] imageBytes = out.toByteArray();
            return BitmapFactory.decodeByteArray(imageBytes, 0, imageBytes.length);
//            // 使用OpenCV进一步压缩
//            Mat mat = Imgcodecs.imdecode(new MatOfByte(imageBytes), Imgcodecs.IMREAD_UNCHANGED);
//            MatOfByte mob = new MatOfByte();
//            Imgcodecs.imencode(".jpg", mat, mob);
//            return mob.toArray();
        } catch (Exception e) {
            XLog.e(e);
            return null;
        }
    }

    public static USBCameraHelper getInstance(Context context) {
        if (instance == null) {
            synchronized (USBCameraHelper.class) {
                if (instance == null) {
                    instance = new USBCameraHelper(context);
                }
            }
        }
        return instance;
    }

    public USBCameraHelper(Context context) {
        mContext = context;
        if (mWorkerHandler == null) {
            mWorkerHandler = HandlerThreadHandler.createHandler(TAG);
            mWorkerThreadID = mWorkerHandler.getLooper().getThread().getId();
        }
        nv21ToBitmap = new NV21ToBitmap(mContext);
        mUSBMonitor = new USBMonitor(mContext, mOnDeviceConnectListener);
    }

    private final Object mSyncUsb = new Object();
    private boolean isAttach = false;

    private final USBMonitor.OnDeviceConnectListener mOnDeviceConnectListener = new USBMonitor.OnDeviceConnectListener() {
        @Override
        public void onAttach(final UsbDevice device) {
            System.out.println("onAttach==>");
            synchronized (mSyncUsb) {
                XLog.i("getDeviceName" + device.getDeviceName() + "getProductId" + device.getProductId() + "getVendorId" + device.getVendorId()
                        + "getDeviceClass" + device.getDeviceClass() + "getProductName" + device.getProductName());
                if (mUSBMonitor != null) {
                    if (device.getDeviceClass() == 239 && !isAttach) {
                        SimpleUsbDevice simpleUsbDevice = CameraLocalRepository.getInstance().getCamera();
                        if (simpleUsbDevice.getVid() != 0 && simpleUsbDevice.getPid() != 0) {
                            if(device.getProductId() == simpleUsbDevice.getPid() && device.getVendorId() == simpleUsbDevice.getVid()){
                                isAttach = true;
                                mUSBMonitor.requestPermission(device);
                            }
                        }else{
                            isAttach = true;
                            mUSBMonitor.requestPermission(device);
                        }
                    }
                }
            }
        }

        @Override
        public void onConnect(final UsbDevice device, final USBMonitor.UsbControlBlock ctrlBlock, final boolean createNew) {
            releaseCamera();
            XLog.d("onConnect===>");
            queueEvent(() -> {
                try {
                    final UVCCamera camera = new UVCCamera();
                    camera.open(ctrlBlock);
                    try {
//                        camera.setPreviewSize(640, 480, UVCCamera.PIXEL_FORMAT_YUV420SP);
                        camera.setPreviewSize(640, 480, UVCCamera.FRAME_FORMAT_YUYV);
                    } catch (final IllegalArgumentException e) {
                        // fallback to YUV mode
                        try {
                            camera.setPreviewSize(640, 480,UVCCamera.PIXEL_FORMAT_YUV420SP);
                        } catch (final IllegalArgumentException e1) {
                            camera.destroy();
                            return;
                        }
                    }
                    camera.setFrameCallback(iFrameCallback, UVCCamera.PIXEL_FORMAT_YUV420SP);
                    if (mSurfaceTexture == null) {
                        mSurfaceTexture = new SurfaceTexture(GLES11Ext.GL_TEXTURE_EXTERNAL_OES);
                    }
                    if (mPreviewSurface == null) {
                        mPreviewSurface = new Surface(mSurfaceTexture);
                    }
                    camera.setPreviewDisplay(mPreviewSurface);
                    camera.startPreview();
                    isFirstFrame = true;
                    synchronized (mSync) {
                        mUVCCamera = camera;
                    }
                } catch (Exception e) {
                    XLog.e(e.toString());
                }
            }, 900);
        }

        @Override
        public void onDisconnect(final UsbDevice device, final USBMonitor.UsbControlBlock ctrlBlock) {
            synchronized (mSyncUsb) {
                long time = System.currentTimeMillis();
                if (time - latestDetachTimestamp < 100) {
                    return;
                }
                isAttach = false;
                latestDetachTimestamp = time;
                XLog.d(String.format("相机vid:%s断开连接", device.getVendorId()));
                releaseCamera();
            }
        }

        @Override
        public void onDetach(final UsbDevice device) {
            System.out.println("onDetach=>");
        }

        @Override
        public void onCancel(final UsbDevice device) {
            System.out.println("onCancel=>");
        }
    };

    /**
     * Release the USB camera device.
     */
    private synchronized void releaseCamera() {
        synchronized (mSync) {
            if (mUVCCamera != null) {
                try {
                    mUVCCamera.stopPreview();
                    mUVCCamera.setStatusCallback(null);
                    mUVCCamera.setButtonCallback(null);
                    mUVCCamera.close();
                    mUVCCamera.destroy();
                    if (mPreviewSurface != null) {
                        mPreviewSurface.release();
                        mPreviewSurface = null;
                    }
                    if (mSurfaceTexture != null) {
                        mSurfaceTexture.release();
                        mSurfaceTexture = null;
                    }
                    XLog.d("uvc相机释放完成");
                } catch (final Exception e) {
                    XLog.d(e.toString());
                }
                mUVCCamera = null;
            }
        }
    }

    public synchronized Bitmap captureStillImage() {
        Bitmap[] bitmap = new Bitmap[1];
//        synchronized (mSyncFrame) {
            try {
                if (frame == null || frame.length <= 0) {
                    System.out.println("抓取图片失败");
                    bitmap[0] = null;
                } else {
                    System.out.println("抓取图片成功");
                    byte[] tempFrame = frame;
                    bitmap[0] = BitmapFactory.decodeByteArray(tempFrame, 0, tempFrame.length);
                    frame = null;
                }
            } catch (Exception e) {
                XLog.e(e.toString());
            }
//        }
        return bitmap[0];
    }

    protected final synchronized void queueEvent(final Runnable task, final long delayMillis) {
        if ((task == null) || (mWorkerHandler == null)) return;
        try {
            mWorkerHandler.removeCallbacks(task);
            if (delayMillis > 0) {
                mWorkerHandler.postDelayed(task, delayMillis);
            } else if (mWorkerThreadID == Thread.currentThread().getId()) {
                task.run();
            } else {
                mWorkerHandler.post(task);
            }
        } catch (final Exception e) {
        }
    }

    public synchronized void open() {
        mUSBMonitor.register();
        synchronized (mSync) {
            if (mUVCCamera != null) {
                mUVCCamera.startPreview();
            }
        }
    }

    public synchronized void close() {
        synchronized (mSync) {
            if (mUVCCamera != null) {
                mUVCCamera.stopPreview();
            }
            if (mUSBMonitor != null) {
                mUSBMonitor.unregister();
            }
        }
    }


    public synchronized void destroy() {
        synchronized (mSync) {
            releaseCamera();
            if (mUSBMonitor != null) {
                mUSBMonitor.destroy();
                mUSBMonitor = null;
            }
            nv21ToBitmap.destroy();
            instance = null;
        }
    }

    public boolean checkCameraOpened() {
        if (mUVCCamera == null) {
            return false;
        }
        return true;
    }

}