package com.sensetime.demo.util;

import android.Manifest;
import android.app.Activity;
import android.content.ContentResolver;
import android.content.Context;
import android.content.UriPermission;
import android.content.pm.PackageManager;
import android.database.Cursor;
import android.graphics.ImageFormat;
import android.graphics.Rect;
import android.graphics.YuvImage;
import android.net.Uri;
import android.os.Build;
import android.provider.OpenableColumns;
import android.text.TextUtils;
import android.util.Log;

import androidx.annotation.RequiresApi;

import com.blankj.utilcode.util.LogUtils;
import com.orhanobut.logger.Logger;


import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileDescriptor;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.MappedByteBuffer;
import java.nio.channels.FileChannel;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.List;


public class FileUtils {
    private static final String TAG = "FileUtils";
    private static final int READ_REQUEST_CODE = 42;
    public static byte[] convertNv21ToJpeg(byte[] nv21, int w, int h, Rect rect) {
        if (rect == null) rect = new Rect(0, 0, w, h);
        YuvImage image = new YuvImage(nv21, ImageFormat.NV21, w, h, null);
        ByteArrayOutputStream outputSteam = new ByteArrayOutputStream();
        image.compressToJpeg(rect, 70, outputSteam);
        return outputSteam.toByteArray();
    }

    public static void writeDataToDisk(byte[] img, String fileName) {
        FileOutputStream fops = null;
        try {
            File file = new File(fileName);
            if(!file.getParentFile().exists()){
                file.getParentFile().mkdirs();
            }
            fops = new FileOutputStream(file);
            fops.write(img);
            fops.flush();
            FileDescriptor fd = fops.getFD();
            fd.sync();
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if(fops != null) {
                try {
                    fops.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    public static Uri getStreamFromExternal(String path) {
//        File externalPubPath = Environment.getExternalStoragePublicDirectory(
//                Environment.DIRECTORY_PICTURES
//        );

        File picPath = new File("/sdcard/SenseTime/m20_V2.2.10_update_tar.bin");
        Uri uri = null;
        if(picPath.exists()) {
            uri = Uri.fromFile(picPath);
        }

        return uri;
    }

    /**
     * 获取文件MD5值
     *
     * @param filePath 文件路径
     *
     * @return
     */
    public static String fileMD5Sync(String filePath) {

        if (TextUtils.isEmpty(filePath)) {
            return "";
        }
        return fileMD5Sync(new File(filePath));
    }

    /**
     * 获取文件MD5值
     *
     * @param file
     *
     * @return
     */
    public static String fileMD5Sync(File file) {

        if (file != null && file.exists()) {
            FileInputStream fis = null;
            try {
                MessageDigest messageDigest = MessageDigest.getInstance("MD5");
                fis = new FileInputStream(file);
                MappedByteBuffer byteBuffer = fis.getChannel().map(FileChannel.MapMode.READ_ONLY, 0, file.length());
                messageDigest.update(byteBuffer);
                BigInteger bigInt = new BigInteger(1, messageDigest.digest());
                String md5 = bigInt.toString(16);
                while (md5.length() < 32) {
                    md5 = "0" + md5;
                }
                return md5;
            } catch (NoSuchAlgorithmException | IOException e) {
                LogUtils.i("exception:"+ e.getMessage());
            } finally {
                if (fis != null) {
                    try {
                        fis.close();
                    } catch (IOException e) {
                        LogUtils.i("exception:"+ e.getMessage());
                    }
                }
            }
        }
        return "";
    }

    @NotNull
    public static String getFileMD5(FileDescriptor file){
        BigInteger bigInt = null;
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            MessageDigest md = MessageDigest.getInstance("MD5");
            byte[] buffer = new byte[1024];
            int length = -1;
            while ((length = fis.read(buffer, 0, 1024)) != -1) {
                md.update(buffer, 0, length);
            }
            bigInt = new BigInteger(1, md.digest());
        } catch (NoSuchAlgorithmException | IOException e) {
            e.printStackTrace();
        }finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        assert bigInt != null;
        StringBuilder hashtext = new StringBuilder(bigInt.toString(16));
        while(hashtext.length() < 32 ){
            hashtext.insert(0, "0");
        }
        return hashtext.toString();
    }

    @Nullable
    public static String getFileName(Uri uri,ContentResolver contentResolver){
        try(Cursor cursor = contentResolver.query(uri,null,null,null,null,null)){
            if(cursor!=null && cursor.moveToFirst()){
                return cursor.getString(cursor.getColumnIndex(OpenableColumns.DISPLAY_NAME));
            }
        }
        return null;
    }

    public static byte[] read(String path){
        Logger.d("path:"+path);
        File imgFile = new File(path);
        FileInputStream imgFIStream = null;
        try {
            imgFIStream = new FileInputStream(imgFile);
            byte[] data = new byte[imgFIStream.available()];
            imgFIStream.read(data);
            return data;
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            if (imgFIStream != null){
                try {
                    imgFIStream.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    public static int getFileSize(Uri uri, ContentResolver contentResolver){
        int fileSize = 0;
        try (Cursor cursor = contentResolver.query(uri, null, null, null, null, null)) {
            if (cursor != null && cursor.moveToFirst()) {
                int sizeIndex = cursor.getColumnIndex(OpenableColumns.SIZE);
                if (!cursor.isNull(sizeIndex)) {
                    fileSize = cursor.getInt(sizeIndex);
                    Logger.d(TAG, "file size:" + fileSize);
                } else {
                    Logger.d(TAG,"Error: can't get file info.");
                    return 0;
                }
            }
        }
        return fileSize;
    }

    public  static long getFileSize(String path){
        File file = new File(path);
        return file.length();
    }


    public static boolean hasExternalSDCardPermission(@NotNull Context context){
        List<UriPermission> permissionList = context.getContentResolver().getPersistedUriPermissions();
        return hasReadPermission(permissionList) && hasWritePermission(permissionList);
    }

    @RequiresApi(api = Build.VERSION_CODES.M)
    public static void showAuthorizeDialog(Activity activity){
        String[] permissions = new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.READ_EXTERNAL_STORAGE};
        for(String pm:permissions){
            if(activity.checkSelfPermission(pm)!=PackageManager.PERMISSION_GRANTED)
                activity.requestPermissions(permissions,READ_REQUEST_CODE);
        }
    }

    private static boolean hasReadPermission(@NotNull List<UriPermission> permissionList){
        for(UriPermission permission : permissionList){
            if(permission.isReadPermission())
                return true;
        }
        return false;
    }

    private static boolean hasWritePermission(@NotNull List<UriPermission> permissionList){
        for(UriPermission permission: permissionList){
            if(permission.isWritePermission())
                return true;
        }
        return false;
    }


}
