package com.ycgis.macall.personalcenter.v.activity;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;

import android.app.ActionBar;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.PointF;
import android.os.Bundle;
import android.provider.MediaStore;
import android.view.View;

import com.google.zxing.BarcodeFormat;
import com.google.zxing.Binarizer;
import com.google.zxing.BinaryBitmap;
import com.google.zxing.ChecksumException;
import com.google.zxing.DecodeHintType;
import com.google.zxing.FormatException;
import com.google.zxing.LuminanceSource;
import com.google.zxing.MultiFormatReader;
import com.google.zxing.NotFoundException;
import com.google.zxing.RGBLuminanceSource;
import com.google.zxing.ReaderException;
import com.google.zxing.Result;
import com.google.zxing.common.GlobalHistogramBinarizer;
import com.google.zxing.common.HybridBinarizer;
import com.google.zxing.qrcode.QRCodeReader;
import com.king.zxing.CameraScan;
import com.king.zxing.CaptureActivity;
import com.king.zxing.DecodeConfig;
import com.king.zxing.DecodeFormatManager;
import com.king.zxing.analyze.MultiFormatAnalyzer;
import com.king.zxing.config.ResolutionCameraConfig;
import com.rs.macall.androidx.basemodel.callback.CustomClickListener;
import com.rs.macall.androidx.basemodel.request.RequestCode;
import com.rs.macall.androidx.basemodel.utils.StatusBarUtil;
import com.rs.macall.androidx.basemodel.utils.ToastUtil;
import com.ycgis.macall.personalcenter.R;
import com.ycgis.macall.personalcenter.p.rxjava.ResultObserver;
import com.ycgis.macall.personalcenter.p.rxjava.UpdateUiOnSubscribe;
import com.ycgis.macall.personalcenter.util.FileUtils;
import com.ycgis.macall.personalcenter.util.ImageOptimizationUtil;
import com.ycgis.macall.personalcenter.util.UriUtils;

import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.TestOnly;

import java.io.File;
import java.io.IOException;
import java.util.EnumMap;
import java.util.HashMap;
import java.util.Hashtable;
import java.util.Map;
import java.util.Vector;

import io.reactivex.Observable;
import io.reactivex.ObservableEmitter;
import io.reactivex.ObservableOnSubscribe;
import io.reactivex.Observer;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.Disposable;
import io.reactivex.schedulers.Schedulers;

import static com.king.zxing.CameraScan.SCAN_RESULT;

public class ScanCodeActivity extends CaptureActivity {

    @Override
    public int getLayoutId() {
        return R.layout.activity_scan_code;
    }

    @Override
    public void initCameraScan() {
        super.initCameraScan();
        StatusBarUtil.setRootViewFitsSystemWindows(this, false);
        //设置状态栏透明
        StatusBarUtil.setTranslucentStatus(this);
//        ActionBar actionBar = getActionBar();
        setActionBar(null);

        //初始化解码配置
        DecodeConfig decodeConfig = new DecodeConfig();
        decodeConfig.setHints(DecodeFormatManager.DEFAULT_HINTS)//如果只有识别二维码的需求，这样设置效率会更高，不设置默认为DecodeFormatManager.DEFAULT_HINTS
                .setFullAreaScan(false)//设置是否全区域识别，默认false
                .setAreaRectRatio(0.8f)//设置识别区域比例，默认0.8，设置的比例最终会在预览区域裁剪基于此比例的一个矩形进行扫码识别
                .setAreaRectVerticalOffset(0)//设置识别区域垂直方向偏移量，默认为0，为0表示居中，可以为负数
                .setAreaRectHorizontalOffset(0);//设置识别区域水平方向偏移量，默认为0，为0表示居中，可以为负数

        // 获取CameraScan，扫码相关的配置设置。CameraScan里面包含部分支持链式调用的方法，即调用返回是CameraScan本身的一些配置建议在startCamera之前调用。
        getCameraScan().setPlayBeep(true)//设置是否播放音效，默认为false
                .setVibrate(true)//设置是否震动，默认为false
                .setCameraConfig(new ResolutionCameraConfig(this))//设置相机配置信息，CameraConfig可覆写options方法自定义配置
                .setNeedAutoZoom(false)//二维码太小时可自动缩放，默认为false
                .setNeedTouchZoom(true)//支持多指触摸捏合缩放，默认为true
                .setDarkLightLux(45f)//设置光线足够暗的阈值（单位：lux），需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效
                .setBrightLightLux(100f)//设置光线足够明亮的阈值（单位：lux），需要通过{@link #bindFlashlightView(View)}绑定手电筒才有效
                .bindFlashlightView(ivFlashlight)//绑定手电筒，绑定后可根据光线传感器，动态显示或隐藏手电筒按钮
                .setOnScanResultCallback(this)//设置扫码结果回调，需要自己处理或者需要连扫时，可设置回调，自己去处理相关逻辑
                .setAnalyzer(new MultiFormatAnalyzer(decodeConfig));//设置是否分析图片，默认为true。如果设置为false，相当于关闭了扫码识别功能

// 启动预览（如果是通过继承CaptureActivity或CaptureFragment实现的则无需调用startCamera）
        getCameraScan().startCamera();
        findViewById(R.id.ivBack).setOnClickListener(v -> finish());
        findViewById(R.id.ivPhotoAlbum).setOnClickListener(new CustomClickListener() {
            @Override
            public void onSingleClick(View v) {
                openSysAlbum();
            }
        });
    }

    /**
     * 打开系统相册
     */
    private void openSysAlbum() {
        Intent albumIntent = new Intent(Intent.ACTION_PICK);
        albumIntent.setDataAndType(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, "image/*");
        startActivityForResult(albumIntent, RequestCode.REQUEST_PHOTO_ALBUM);
    }

    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable @org.jetbrains.annotations.Nullable Intent data) {
        if (requestCode == RequestCode.REQUEST_PHOTO_ALBUM) {
            if (data == null) {
                ToastUtil.centered(this, "选择照片失败！");
                return;
            }
            String ss = UriUtils.getRealPathFromUri(this, data.getData());
            File photoFile = new File(ss);
            if (!photoFile.exists()) {
                ToastUtil.centered(ScanCodeActivity.this, "文件不存在！");
                return;
            }
            decodeQRCodeSync(photoFile);
//            Bitmap bitmap = BitmapFactory.decodeFile(photoFile.getAbsolutePath());
//            if (bitmap == null){
//                ToastUtil.centered(ScanCodeActivity.this,"错误的图片！");
//                return;
//            }
//            decodeQRCodeSync(bitmap);
        }
        super.onActivityResult(requestCode, resultCode, data);
    }

    private void decodeQRCodeSync(File file) {
        Observable.create(new UpdateUiOnSubscribe<File, String>(file) {

            @Override
            public void subscribe(File date, @NotNull ObservableEmitter<String> emitter) {
                Bitmap decodeAbleBitmap = getDecodeAbleBitmap(date.getAbsolutePath());
                if (decodeAbleBitmap==null){
                    emitter.onError(new Exception("错误的图片路径！"));
                    emitter.onComplete();
                    return;
                }
                String s = syncDecodeQRCode(decodeAbleBitmap);
                if (s == null){
                    emitter.onError(new Exception("错误的图片路径！"));
                    emitter.onComplete();
                    return;
                }
                emitter.onNext(s);
                emitter.onComplete();
            }
        })
                .subscribeOn(Schedulers.io())
                .observeOn(AndroidSchedulers.mainThread())
                .subscribe(new ResultObserver<String>("s") {
                    @Override
                    protected void onNext(String identifierKey, @NotNull String data) {
                        Intent intent = new Intent();
                        intent.putExtra(SCAN_RESULT, data);
                        setResult(Activity.RESULT_OK, intent);
                        finish();
                    }

                    @Override
                    public void onError(@NotNull Throwable e) {
                        ToastUtil.centered(ScanCodeActivity.this, "识别失败！");
                    }
                });
    }


    /**
     * 扫码结果回调
     *
     * @param result
     * @return 返回false表示不拦截，将关闭扫码界面并将结果返回给调用界面；
     * 返回true表示拦截，需自己处理逻辑。当isAnalyze为true时，默认会继续分析图像（也就是连扫）。
     * 如果只是想拦截扫码结果回调，并不想继续分析图像（不想连扫），请在拦截扫码逻辑处通过调
     * 用{@link CameraScan#setAnalyzeImage(boolean)}，
     * 因为{@link CameraScan#setAnalyzeImage(boolean)}方法能动态控制是否继续分析图像。
     */
    @Override
    public boolean onScanResultCallback(Result result) {
        getCameraScan().setAnalyzeImage(false);
        /*
         * 因为setAnalyzeImage方法能动态控制是否继续分析图像。
         *
         * 1. 因为分析图像默认为true，如果想支持连扫，返回true即可。
         * 当连扫的处理逻辑比较复杂时，请在处理逻辑前调用getCameraScan().setAnalyzeImage(false)，
         * 来停止分析图像，等逻辑处理完后再调用getCameraScan().setAnalyzeImage(true)来继续分析图像。
         *
         * 2. 如果只是想拦截扫码结果回调自己处理逻辑，但并不想继续分析图像（即不想连扫），可通过
         * 调用getCameraScan().setAnalyzeImage(false)来停止分析图像。
         */
//        Intent intent = new Intent();
//        intent.putExtra("IdentifyingContent",result.getText());
//        setResult(Activity.RESULT_OK,intent);

        return super.onScanResultCallback(result);
    }



    /**
     * 将本地图片文件转换成可解码二维码的 Bitmap。为了避免图片太大，这里对图片进行了压缩。
     *
     * @param picturePath 本地图片文件路径
     */
    public static Bitmap getDecodeAbleBitmap(String picturePath) {
        try {
            BitmapFactory.Options options = new BitmapFactory.Options();
            options.inJustDecodeBounds = true;
            BitmapFactory.decodeFile(picturePath, options);
            int sampleSize = options.outHeight / 400;
            if (sampleSize <= 0) {
                sampleSize = 1;
            }
            options.inSampleSize = sampleSize;
            options.inJustDecodeBounds = false;

            return BitmapFactory.decodeFile(picturePath, options);
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        }
    }
    /**
     * 同步解析bitmap二维码。该方法是耗时操作，请在子线程中调用。
     *
     * @param bitmap 要解析的二维码图片
     * @return 返回二维码图片里的内容 或 null
     */
    public static String syncDecodeQRCode(Bitmap bitmap) {
        Result result;
        RGBLuminanceSource source = null;
        try {
            int width = bitmap.getWidth();
            int height = bitmap.getHeight();
            int[] pixels = new int[width * height];
            bitmap.getPixels(pixels, 0, width, 0, 0, width, height);
            source = new RGBLuminanceSource(width, height, pixels);
            result = new MultiFormatReader().decode(new BinaryBitmap(new HybridBinarizer(source)), new EnumMap<>(DecodeHintType.class));
            return result.getText();
        } catch (Exception e) {
            e.printStackTrace();
            if (source != null) {
                try {
                    result = new MultiFormatReader().decode(new BinaryBitmap(new GlobalHistogramBinarizer(source)), new EnumMap<>(DecodeHintType.class));
                    return result.getText();
                } catch (Throwable e2) {
                    e2.printStackTrace();
                }
            }
            return null;
        }
    }
}