package com.videogo.util;

import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.MediaStore;
import android.text.TextUtils;
import android.util.Log;
import android.widget.ImageView;

import com.bumptech.glide.Glide;
import com.bumptech.glide.load.ResourceDecoder;
import com.bumptech.glide.load.engine.DiskCacheStrategy;
import com.bumptech.glide.load.engine.Resource;
import com.bumptech.glide.load.resource.bitmap.BitmapResource;
import com.bumptech.glide.load.resource.drawable.GlideDrawable;
import com.bumptech.glide.request.RequestListener;
import com.bumptech.glide.request.target.Target;
import com.videogo.EzvizApplication;
import com.videogo.exception.InnerException;
import com.videogo.openapi.bean.EZAlarmInfo;
import com.videogo.openapi.bean.EZCameraInfo;
import com.videogo.openapi.bean.EZDeviceInfo;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.nio.file.Files;

import ezviz.ezopensdk.R;

public class EZUtils {

    private final static String TAG = EZUtils.class.getSimpleName();

    public static void saveCapturePictrue(String filePath, Bitmap bitmap) throws InnerException {
        if (TextUtils.isEmpty(filePath)) {
            LogUtil.d("EZUtils", "saveCapturePictrue file is null");
            return;
        }
        File filepath = new File(filePath);
        File parent = filepath.getParentFile();
        if (parent == null || !parent.exists() || parent.isFile()) {
            parent.mkdirs();
        }
        FileOutputStream out = null;
        try {
            // 保存原图

            if (!TextUtils.isEmpty(filePath)) {
                out = new FileOutputStream(filepath);
                bitmap.compress(CompressFormat.JPEG, 100, out);
                //out.write(tempBuf, 0, size);
                out.flush();
                out.close();
                out = null;
            }


        } catch (FileNotFoundException e) {
//            throw new InnerException(e.getLocalizedMessage());
            e.printStackTrace();
        } catch (IOException e) {
//            throw new InnerException(e.getLocalizedMessage());
            e.printStackTrace();
        } finally {
            if (out != null) {
                try {
                    out.close();
                } catch (IOException e) {
                    // TODO Auto-generated catch block
                    e.printStackTrace();
                }
            }
        }
    }


    public static Object getPrivateMethodInvoke(Object instance, /*Class destClass,*/ String methodName,
                                                Class<?>[] parameterClass, Object... args) throws Exception {
        Class<?>[] parameterTypes = null;
        if (args != null) {
            parameterTypes = parameterClass;
        }
        Method method = instance.getClass().getDeclaredMethod(methodName, parameterTypes);
        method.setAccessible(true);
        return method.invoke(instance, args);
    }

    public static EZCameraInfo getCameraInfoFromDevice(EZDeviceInfo deviceInfo, int camera_index) {
        if (deviceInfo == null) {
            return null;
        }
        // 没有通道信息，则取子设备信息；如果自己的设备没有挂载在网关下的话，不用考虑子设备
        if (deviceInfo.getCameraInfoList() != null && deviceInfo.getCameraInfoList().size() > camera_index) {// 通道信息
            return deviceInfo.getCameraInfoList().get(camera_index);
        } else if (deviceInfo.getSubDeviceInfoList() != null && deviceInfo.getSubDeviceInfoList().size() > camera_index) {// 子设备信息
            return deviceInfo.getSubDeviceInfoList().get(camera_index);
        }
        return null;
    }

    public static EZDeviceInfo CopyEzDeviceInfoNoCameraAndDetector(EZDeviceInfo deviceInfo) {
        if (deviceInfo == null) {
            return null;
        }
        EZDeviceInfo ezDeviceInfo = new EZDeviceInfo();
        ezDeviceInfo.setDeviceName(deviceInfo.getDeviceName());
        ezDeviceInfo.setIsEncrypt(deviceInfo.getIsEncrypt());
        ezDeviceInfo.setCameraNum(deviceInfo.getCameraNum());
        ezDeviceInfo.setDefence(deviceInfo.getDefence());
        return deviceInfo;
    }

    private static boolean isEncrypt(String url) {
        int ret = 0;
        try {
            String keyOfTargetValue = "isEncrypted";
            String strIsEncrypted = Uri.parse(url).getQueryParameter(keyOfTargetValue);
            if (strIsEncrypted != null) {
                ret = Integer.parseInt(strIsEncrypted);
            } else {
                LogUtil.e(TAG, "not find key: " + keyOfTargetValue);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return ret == 1;
    }

    public static void loadImage(final Context context, final ImageView imageView, final EZAlarmInfo alarmInfo,
                                 final VerifyCodeInput.VerifyCodeErrorListener verifyCodeErrorListener) {
        if (alarmInfo == null) {
            return;
        }
        if (!isEncrypt(alarmInfo.getAlarmPicUrl())) {
            Glide.with(context).load(alarmInfo.getAlarmPicUrl()).placeholder(R.drawable.record_cover_placeholder).listener(new RequestListener<String, GlideDrawable>() {
                @Override
                public boolean onException(Exception e, String s, Target<GlideDrawable> target, boolean b) {
                    if (e != null) {
                        e.printStackTrace();
                    }
                    return false;
                }

                @Override
                public boolean onResourceReady(GlideDrawable glideDrawable, String s, Target<GlideDrawable> target,
                                               boolean b, boolean b1) {
                    return false;
                }
            }).error(R.drawable.event_list_fail_pic).into(imageView);
        } else {
            int crypt = 0;
            String pwd = "";
            if (alarmInfo.getCrypt() != 2) { //兼容不支持的服务，继续走旧的默认的设备加密
                crypt = 1;
                pwd = DataManager.getInstance().getDeviceSerialVerifyCode(alarmInfo.getDeviceSerial());
            } else {
                crypt = 2;
                pwd = alarmInfo.getChecksum();
            }

            if (TextUtils.isEmpty(pwd)) {
                imageView.setImageResource(R.drawable.alarm_encrypt_image_mid);
                if (verifyCodeErrorListener != null) {
                    verifyCodeErrorListener.verifyCodeError();
                }
                return;
            }
            final int finalCrypt = crypt;
            final String finalPwd = pwd;
            Glide.with(context).load(alarmInfo.getAlarmPicUrl()).asBitmap()
                    /**************图片加载监听，打印错误信息*************************/.listener(new RequestListener<String,
                    Bitmap>() {
                @Override
                public boolean onException(Exception e, String model, Target<Bitmap> target, boolean isFirstResource) {
                    if (e != null) {
                        e.printStackTrace();
                    }
                    return false;
                }

                @Override
                public boolean onResourceReady(Bitmap resource, String model, Target<Bitmap> target,
                                               boolean isFromMemoryCache, boolean isFirstResource) {
                    return false;
                }
            }).placeholder(R.drawable.record_cover_placeholder)
                    /**************加密图片本地文件缓存,开发者自己决定缓存机制*******************/.diskCacheStrategy(DiskCacheStrategy.RESULT).error(R.drawable.event_list_fail_pic).imageDecoder(new ResourceDecoder<InputStream, Bitmap>() {
                @Override
                public Resource<Bitmap> decode(InputStream source, int width, int height) throws IOException {
                    ByteArrayOutputStream output = new ByteArrayOutputStream();
                    byte[] buffer = new byte[4096];
                    Bitmap desBitmap = null;
                    int n = 0;
                    while (-1 != (n = source.read(buffer))) {
                        output.write(buffer, 0, n);
                    }
                    output.flush();
                    output.close();
                    byte[] src = output.toByteArray();
                    if (src == null || src.length <= 0) {
                        LogUtil.d("EZUTils", "图片加载错误！");
                        return null;
                    }
                    if (!isEncrypt(alarmInfo.getAlarmPicUrl())) {
                        desBitmap = BitmapFactory.decodeByteArray(src, 0, src.length);
                    } else {
                        /*************** 开发者需要调用此接口解密 ****************/
                        byte[] data1 = EzvizApplication.getOpenSDK().decryptData(output.toByteArray(), finalPwd,
                                finalCrypt);
                        if (data1 == null || data1.length <= 0) {
                            LogUtil.d("EZUTils", "verifyCodeError！");
                            /*************** 验证码错误 ,此处回调是在子线程中，处理UI需调回到主线程****************/
                            if (verifyCodeErrorListener != null) {
                                verifyCodeErrorListener.verifyCodeError();
                            }
                        } else {
                            desBitmap = BitmapFactory.decodeByteArray(data1, 0, data1.length);
                        }
                    }

                    if (desBitmap != null) {
                        return new BitmapResource(desBitmap, DataManager.getInstance().getBitmapPool(context));
                    }
                    return null;
                }

                @Override
                public String getId() {
                    return alarmInfo.getAlarmPicUrl();
                }
            }).into(imageView);
        }
    }

    /**
     * 保存图片
     *
     * @param context
     * @param file
     */
    public static void savePicture2Album(Context context, File file) {
        // 是否添加到相册
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            ContentResolver localContentResolver = context.getContentResolver();
            ContentValues localContentValues = getPictureContentValues(file, System.currentTimeMillis());
            Uri localUri = localContentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    localContentValues);
        } else {
            try {
                Uri uri = Uri.fromFile(file);
                MediaStore.Images.Media.insertImage(context.getContentResolver(), file.getAbsolutePath(), null, null);
                context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, uri));
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        }
    }

    /**
     * 保存图片
     *
     * @param toBitmap
     */
    public static void savePicture2Album(Context context, Bitmap toBitmap) {
        // 是否添加到相册
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            // 开始一个新的进程执行保存图片的操作
            ContentResolver localContentResolver = context.getContentResolver();
            Uri insertUri = localContentResolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI,
                    new ContentValues());
            // 使用use可以自动关闭流
            try {
                OutputStream outputStream = context.getContentResolver().openOutputStream(insertUri, "rw");
                if (toBitmap.compress(Bitmap.CompressFormat.JPEG, 90, outputStream)) {
                    LogUtil.d("EZUtils", "save picture success");
                } else {
                    Log.e("EZUtils", "save picture fail");
                }
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
        } else {
            MediaStore.Images.Media.insertImage(context.getContentResolver(), toBitmap, null, null);
        }
    }

    private static ContentValues getPictureContentValues(File paramFile, long paramLong) {
        ContentValues localContentValues = new ContentValues();
        localContentValues.put(MediaStore.MediaColumns.TITLE, paramFile.getName());
        localContentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, paramFile.getName());
        localContentValues.put(MediaStore.MediaColumns.MIME_TYPE, "image/jpeg");
        localContentValues.put(MediaStore.MediaColumns.DATE_TAKEN, Long.valueOf(paramLong));
        localContentValues.put(MediaStore.MediaColumns.DATE_MODIFIED, Long.valueOf(paramLong));
        localContentValues.put(MediaStore.MediaColumns.DATE_ADDED, Long.valueOf(paramLong));
        localContentValues.put(MediaStore.MediaColumns.DATA, paramFile.getAbsolutePath());
        localContentValues.put(MediaStore.MediaColumns.SIZE, Long.valueOf(paramFile.length()));

        return localContentValues;
    }

    /**
     * 保存视频
     *
     * @param context
     * @param file
     */
    public static void saveVideo2Album(Context context, File file, long duration) {
        if (file == null || !file.exists()) {
            Log.e(TAG, "saveVideo2Album: file is null or not exists");
            return;
        }

        new Thread(() -> {
            try {
                ContentResolver localContentResolver = context.getContentResolver();
                ContentValues localContentValues = getVideoContentValues(context, file, System.currentTimeMillis(),
                        duration);
                Uri localUri = localContentResolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI,
                        localContentValues);

                if (localUri == null) {
                    Log.e(TAG, "saveVideo2Album: insert failed, localUri is null");
                    return;
                }

                // Android 10+ 使用分区存储
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
                    try (OutputStream outputStream = localContentResolver.openOutputStream(localUri)) {
                        if (outputStream != null) {
                            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.R) {
                                // Android 11+ 使用 Files.copy
                                Files.copy(file.toPath(), outputStream);
                            } else {
                                // Android 10 使用传统IO复制
                                try (InputStream inputStream = Files.newInputStream(file.toPath())) {
                                    byte[] buffer = new byte[8192];
                                    int bytesRead;
                                    while ((bytesRead = inputStream.read(buffer)) != -1) {
                                        outputStream.write(buffer, 0, bytesRead);
                                    }
                                }
                            }
                            Log.d(TAG, "saveVideo2Album: save success with scoped storage");
                        }
                    }
                } else {
                    // Android 9 及以下使用旧方式
                    context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, Uri.fromFile(file)));
                    Log.d(TAG, "saveVideo2Album: save success with legacy method");
                }

                // 发送媒体扫描广播（适用于Android 10以下）
                if (Build.VERSION.SDK_INT < Build.VERSION_CODES.Q) {
                    context.sendBroadcast(new Intent(Intent.ACTION_MEDIA_SCANNER_SCAN_FILE, localUri));
                }
            } catch (Exception e) {
                Log.e(TAG, "saveVideo2Album: save failed", e);
                e.printStackTrace();
            }
        }).start();
    }


    private static ContentValues getVideoContentValues(Context context, File paramFile, long paramLong, long duration) {
        ContentValues localContentValues = new ContentValues();
        localContentValues.put(MediaStore.MediaColumns.TITLE, paramFile.getName());
        localContentValues.put(MediaStore.MediaColumns.DISPLAY_NAME, paramFile.getName());
        localContentValues.put(MediaStore.MediaColumns.MIME_TYPE, "video/mp4");
        localContentValues.put(MediaStore.MediaColumns.DATE_TAKEN, paramLong);
        localContentValues.put(MediaStore.MediaColumns.DATE_MODIFIED, paramLong);
        localContentValues.put(MediaStore.MediaColumns.DATE_ADDED, paramLong);
        localContentValues.put(MediaStore.MediaColumns.DURATION, duration * 1000);
        localContentValues.put(MediaStore.MediaColumns.SIZE, paramFile.length());
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.UPSIDE_DOWN_CAKE) {
            localContentValues.put(MediaStore.MediaColumns.RELATIVE_PATH, Environment.DIRECTORY_MOVIES);
        } else if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
            localContentValues.put(MediaStore.MediaColumns.RELATIVE_PATH,
                    Environment.DIRECTORY_DCIM + File.separator + context.getPackageName());
        } else {
            localContentValues.put(MediaStore.MediaColumns.DATA, paramFile.getAbsolutePath());
        }

        return localContentValues;
    }

}
