package com.naz.sdkdemo.picselect;

import android.Manifest;
import android.app.Activity;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.Looper;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;

import androidx.annotation.IntDef;
import androidx.core.app.ActivityCompat;
import androidx.core.content.FileProvider;


import com.naz.sdkdemo.R;
import com.naz.sdkdemo.utils.BitmapUtils;
import com.naz.sdkdemo.utils.LogUtils;

import java.io.File;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

/**
 * Created by sunjc on 2018/4/10.
 */

public class SPictureSelector {
    //结果以文件格式返回
    public static final int RESULT_FILE = 0;
    //结果以byte[]格式返回
    public static final int RESULT_BYTE = 1;
    //结果以bitmap格式返回
    public static final int RESULT_BITMAP = 2;

    @IntDef({RESULT_FILE,RESULT_BYTE,RESULT_BITMAP})
    @Retention(RetentionPolicy.SOURCE)
    public @interface ResultType{}

    public static final int PHOTO_REQUEST_CAMERA = 1;// 相机读取
    public static final int PHOTO_REQUEST_FILE = 2;// 文件中读取
    public static final int PHOTO_REQUEST_CUT = 3;
    public static final int MAX_VIDEO_DURATION = 15000;//视频最大时长

    private Activity context;
    private String temp_name = "temp_picture.jpg";
    private File tempPictureFile = null;
    private Uri tempPictureUri;
    private ResultCallback callback;
    //返回结果是file还是byte[] 数组
    private @ResultType int resultType;
    private byte[] bytes;
    private String sourceFilePath;
    private Uri outFileUri;
    //图片结果是否需要裁剪
    private boolean needCut = false;
    //目标宽度和高度
    private int outWidth,outHeight;
    private int targetImageSize;
    private int targetVideoDura = MAX_VIDEO_DURATION;

    private ExecutorService executor;
    private Handler handler;
    private static final int PERMISSIONS_REQUEST_FILE = 1;
    //当前操作为camera
    private boolean camera = false;
    private MediaInfo mediaInfo;

    public SPictureSelector(Context context, @ResultType int resultType){
        if (!(context instanceof Activity)){
            throw new IllegalArgumentException("context must is Activity");
        }
        this.context = (Activity) context;
        this.resultType = resultType;
        executor = Executors.newFixedThreadPool(2);
        handler = new Handler(Looper.getMainLooper());
    }

    public SPictureSelector(Activity context, @ResultType int resultType){
        this.context = context;
        this.resultType = resultType;
        executor = Executors.newFixedThreadPool(2);
        handler = new Handler(Looper.getMainLooper());
    }

    /**
     * 设置裁剪玩之后图片的宽和高
     * @param outHeight
     * @param outWidth
     */
    public void setOutSize(int outWidth,int outHeight){
        needCut = true;
        this.outHeight = outHeight;
        this.outWidth = outWidth;
    }

    /**
     * 设置最终图片的大小
     * @param size 图片大小(单位为kb)
     */
    public void setTargetImageSize(int size){
        targetImageSize = size;
    }

    public void setTargetVideoDura(int targetVideoDura) {
        this.targetVideoDura = targetVideoDura;
    }

    public void setCallback(ResultCallback callback) {
        this.callback = callback;
    }

    /**
     * 相机拍照
     */
    public void fromCamera(){
        camera = true;
        mediaInfo = null;
        if (checkFilePermission(true)){
            fromCameraInner();
        }
    }

    private void fromCameraInner(){
        Intent intent = new Intent("android.media.action.IMAGE_CAPTURE");
        File cameraPhoto = tempFile(Build.VERSION.SDK_INT >= Build.VERSION_CODES.N);
        Uri photoUri = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            photoUri = FileProvider.getUriForFile(context,context.getPackageName() + ".fileprovider", cameraPhoto);
        }else {
            photoUri = Uri.fromFile(cameraPhoto);
        }
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        tempPictureUri = photoUri;
        intent.putExtra(MediaStore.EXTRA_OUTPUT, photoUri);

        //intent.putExtra(MediaStore.EXTRA_OUTPUT, Uri.fromFile(tempFile()));
        context.startActivityForResult(intent, PHOTO_REQUEST_CAMERA);
    }

    /**
     * 从图库中选择
     */
    public void fromGallery(){
       camera = false;
        mediaInfo = null;
       if (checkFilePermission(false)){
           fromGalleryInner();
       }
    }

    private void fromGalleryInner(){
        Intent intent = new Intent(Intent.ACTION_PICK);
        intent.setType("image/*");
        //intent.setType("video/*");
        context.startActivityForResult(intent, PHOTO_REQUEST_FILE);
    }

    /**
     * 裁剪
     * @param filePath 图片资源路径
     */
    public void cut(String filePath) {
        // 裁剪图片意图
        Intent intent = new Intent("com.android.camera.action.CROP");
        intent.putExtra("crop", "true");
        // 裁剪框比例
        intent.putExtra("aspectX", 1);
        intent.putExtra("aspectY", 1);
        // 裁剪输出图片大小
        if (outWidth > 0 && outHeight > 0) {
            intent.putExtra("outputX", outWidth);
            intent.putExtra("outputY", outHeight);
        }
        // 图片格式
        intent.putExtra("outputFormat", "JPEG");
        intent.putExtra("noFaceDetection", true);// 取消人脸识别
        /**
         * 此方法返回的图片只能是小图片（sumsang测试为高宽160px的图片）
         * 故将图片保存在Uri中，调用时将Uri转换为Bitmap，此方法还可解决miui系统不能return data的问题
         */
//        intent.putExtra("return-data", true);// true不返回uri，false 返回uri
        String pkName = context.getPackageName();
        sourceFilePath = getCutResultFilePath();
        Uri fileOutputUri = null;
        Uri fileInputUri = null;
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
            intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
            fileOutputUri = Uri.fromFile(new File(sourceFilePath));
            fileInputUri = FileProvider.getUriForFile(context,context.getPackageName() + ".fileprovider", new File(filePath));
        }else {
            fileOutputUri = Uri.parse("file://" + "/" + sourceFilePath);
            fileInputUri = Uri.fromFile(new File(filePath));
        }
        outFileUri = fileOutputUri;
        intent.setDataAndType(fileInputUri, "image/*");
        intent.putExtra(MediaStore.EXTRA_OUTPUT, fileOutputUri);
//        intent.putExtra("outputFormat", Bitmap.CompressFormat.JPEG.toString());
        context.startActivityForResult(intent, PHOTO_REQUEST_CUT);
    }

    public void onActivityResult(int requestCode, int resultCode, Intent data){
        if (requestCode == PHOTO_REQUEST_FILE && resultCode == Activity.RESULT_OK) {
            if (data != null) {
                // 得到图片的全路径
                Uri uri = data.getData();
                String[] filePathColumn = {MediaStore.Images.Media.DATA, MediaStore.Images.Media.MIME_TYPE,
                        MediaStore.Images.Media.SIZE, MediaStore.Images.Media.WIDTH,
                        MediaStore.Images.Media.HEIGHT};
                Cursor cursor = context.getContentResolver().query(uri,
                        filePathColumn, null, null, null);//从系统表中查询指定Uri对应的照片
                cursor.moveToFirst();
                int columnIndex = cursor.getColumnIndex(filePathColumn[0]);
                MediaInfo info = new MediaInfo();
                String path  = cursor.getString(columnIndex);  //获取照片路径
                info.path = path;
                info.mineType = cursor.getString(cursor.getColumnIndex(filePathColumn[1]));
                info.size = cursor.getLong(cursor.getColumnIndex(filePathColumn[2]));
                info.width = cursor.getInt(cursor.getColumnIndex(filePathColumn[3]));
                info.height = cursor.getInt(cursor.getColumnIndex(filePathColumn[4]));
                cursor.close();
                mediaInfo = info;
                //判断视频有么有超过最大值
                if (info.isVideo() && info.duration > targetVideoDura) {
                    Toast.makeText(context,context.getResources().getString(R.string.no_collect_set_text), Toast.LENGTH_LONG).show();
                    return;
                }
                if (needCut && info.isImage()) {
                    cut(path);
                    return;
                }
                sourceFilePath = path;
                callBackResult();
            }
        } else if (requestCode == PHOTO_REQUEST_CAMERA && resultCode == Activity.RESULT_OK) {
            Log.i("resultCode", "resultCode=" + resultCode);
            File tempFile = tempPictureFile;
            //tempFile = new File(tempPictureUri.getPath());

            if (tempFile.exists()) {
                if (needCut) {
                    cut(tempFile.getAbsolutePath());
                    return;
                }
                sourceFilePath = tempFile.getAbsolutePath();
                mediaInfo = new MediaInfo();
                mediaInfo.path = sourceFilePath;
                callBackResult();
            } else {
                Toast.makeText(context,context.getResources().getString(R.string.no_collect_set_text), Toast.LENGTH_LONG).show();
            }
        }else if (requestCode == PHOTO_REQUEST_CUT && resultCode == Activity.RESULT_OK){
            LogUtils.D("outFileUri=" + outFileUri);
            callBackResult();
        }else if (resultCode == context.RESULT_CANCELED) {
            if (tempPictureFile != null) {
                tempPictureFile.delete();
            }
        }
    }

    private void callBackResult() {
        if (null == callback || null == mediaInfo){
            return;
        }
        callback.begin();
        if (mediaInfo.isVideo()) {
            callback.end();
            callback.result(true, new File(mediaInfo.path));
            return;
        }
        compress(new CompressCallback() {
            @Override
            public void result(final Bitmap bitmap) {
                if (null == bitmap ){
                    return;
                }
                callback.end();
                final File outFile = new File(sourceFilePath);
                if (resultType == RESULT_FILE){
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            callback.result(false, outFile);
                        }
                    });
                    bitmap.recycle();
                    return;
                }
                if (resultType == RESULT_BYTE){
                    final byte[] result = BitmapUtils.bitmap2Bytes(bitmap,100, Bitmap.CompressFormat.JPEG);
                    bitmap.recycle();
                    handler.post(new Runnable() {
                        @Override
                        public void run() {
                            callback.result(result);
                        }
                    });
                    return;
                }
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        callback.result(bitmap);
                    }
                });
            }
        });
    }

    /**
     * 图片压缩(质量压缩法)
     */
    private void compress(final CompressCallback callback){
        executor.submit(new Runnable() {
            @Override
            public void run() {
                Bitmap bitmap = BitmapFactory.decodeFile(sourceFilePath);
                int angle = BitmapUtils.obtainPictureDegree(sourceFilePath);
                if (angle > 0) {
                    bitmap = BitmapUtils.rotatingBitmap(angle,bitmap);
                }
                if (targetImageSize <= 0){
                    callback.result(bitmap);
                    return;
                }
                int quality = 100;
                byte[] bytes = BitmapUtils.bitmap2Bytes(bitmap,quality, Bitmap.CompressFormat.JPEG);
                while (null != bytes && bytes.length > targetImageSize * 1024){
                    quality -= 5;
                    bitmap = BitmapUtils.compressByQuality(bitmap, quality);
                    bytes = BitmapUtils.bitmap2Bytes(bitmap,quality, Bitmap.CompressFormat.JPEG);
                }
                final Bitmap resultBitmap = bitmap;
                String savePath = new File(getFilePath(false), temp_name).getAbsolutePath();
                BitmapUtils.save(context, bitmap, savePath, Bitmap.CompressFormat.JPEG, quality,false, new BitmapUtils.BitmapSave2FileCallback() {
                    @Override
                    public void saveResult(boolean success) {
                        callback.result(resultBitmap);
                    }
                });
            }
        });
    }

    /**
     * 关闭
     */
    public void close(){
        executor.shutdown();
        try {
            executor.awaitTermination(1, TimeUnit.SECONDS);
        } catch (InterruptedException e) {
            e.printStackTrace();
            executor = null;
        }
    }

    /**
     * 获取裁剪之后的保存的图片路径
     * @return
     */
    private String getCutResultFilePath(){
        return getFilePath(false) + "picture_select"+ "_"+ System.currentTimeMillis()+".jpg";//+ System.currentTimeMillis()
    }

    /**
     * 生成临时文件
     * @return
     */
    private File tempFile(boolean internal){
        tempPictureFile = new File(getFilePath(internal), temp_name);
        return tempPictureFile;
    }

    /**
     * 获取文件保存的目录
     * @return
     */
    private String getFilePath(boolean internal){
        //获取当前包名
        String pkName = context.getPackageName();
        String path = null;
        if (internal || !hasSDCard()){
            path = context.getFilesDir().getAbsolutePath()+"/photo/";
        }else  if (hasSDCard()){
            path = context.getExternalFilesDir("data").getAbsolutePath()+"/"+ pkName+"/photo/";
        }
        File file = new File(path);
        if (!file.exists()){
            file.mkdirs();
        }
        return path;
    }

    /**
     * 判断是否有sd卡
     * @return
     */
    private boolean hasSDCard(){
        if (Environment.getExternalStorageState().equals(
                Environment.MEDIA_MOUNTED)) {
            return true;
        } else {
            return false;
        }
    }

    /**
     * 检查文件权限
     */
    private boolean checkFilePermission(boolean camera){
        String[] PERMISSIONS_STORAGE = camera ? new String[]{
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
                Manifest.permission.CAMERA
        } : new String[]{
                Manifest.permission.READ_EXTERNAL_STORAGE,
                Manifest.permission.WRITE_EXTERNAL_STORAGE,
        };
        int permission = ActivityCompat.checkSelfPermission(context, Manifest.permission.WRITE_EXTERNAL_STORAGE);
        int permission2 = camera ? ActivityCompat.checkSelfPermission(context, Manifest.permission.CAMERA) :
                PackageManager.PERMISSION_GRANTED;

        if (permission != PackageManager.PERMISSION_GRANTED || permission2 != PackageManager.PERMISSION_GRANTED) {
            // We don't have permission so prompt the user
            ActivityCompat.requestPermissions(context,PERMISSIONS_STORAGE,PERMISSIONS_REQUEST_FILE);
            return false;
        }
        return true;
    }

    /**
     * 如果返回类型为File，必须在Activity onRequestPermissionsResult中调用
     * @param requestCode
     * @param permissions
     * @param grantResults
     */
    public void onRequestPermissionsResult(int requestCode,
                                           String permissions[], int[] grantResults) {
        switch (requestCode) {
            case PERMISSIONS_REQUEST_FILE: {
                // If request is cancelled, the result arrays are empty.
                if (grantResults.length > 0
                        && grantResults[0] == PackageManager.PERMISSION_GRANTED) {

                    // permission was granted, yay! Do the
                    // contacts-related task you need to do.
                    if (camera){
                        fromCameraInner();
                        return;
                    }
                    fromGalleryInner();
                } else {

                    // permission denied, boo! Disable the
                    // functionality that depends on this permission.
                }
                return;
            }
        }
    }

    public interface ResultCallback{
        //file格式返回
        public void result(boolean video, File file);
        //二进制返回
        public void result(byte[] bytes);
        //bitmap返回
        public void result(Bitmap bitmap);
        //结果处理开始
        void begin();
        //结果处理结束
        void end();
    }

    public static abstract class ResultCallbackAdapter implements ResultCallback{
        @Override
        public void result(boolean video, File file) {

        }

        @Override
        public void result(byte[] bytes) {

        }

        @Override
        public void result(Bitmap bitmap) {

        }

        @Override
        public void begin() {

        }

        @Override
        public void end() {

        }
    }

    private interface CompressCallback{
        public void result(Bitmap bitmap);
    }

    private static class MediaInfo {
        String path;//获取照片路径
        String mineType; //类型
        long size; //大小
        long duration; //时长
        int width; //宽
        int height; //高

        private boolean isVideo() {
            if (TextUtils.isEmpty(mineType)) {
                return false;
            }
            return mineType.startsWith("video/");
        }

        private boolean isImage() {
            if (TextUtils.isEmpty(mineType)) {
                return false;
            }
            return mineType.startsWith("image/");
        }
    }
}
