package com.eitchsyh.instrument.eitc_erm_dental_flutter;

import android.app.RecoverableSecurityException;
import android.content.ContentUris;
import android.content.Context;
import android.content.IntentSender;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.provider.MediaStore;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

import io.flutter.Log;
import io.flutter.embedding.engine.FlutterEngine;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;

/**
 * 文件控制器
 */
public class FileController implements MethodChannel.MethodCallHandler
{
    public interface OnDeleteFileRequestPermissionListener
    {
        void onDeleteFileRequestPermission(IntentSender sender);
    }

    private final String TAG = "FileController";

    private final Context context;
    private final FlutterEngine flutterEngine;
    private final MethodChannel channel;
    private MethodChannel.Result tempDeleteFileResult;
    private Uri tempDeleteFileUri;

    private OnDeleteFileRequestPermissionListener onDeleteFileRequestPermission;

    public FileController(@NonNull Context context, @NonNull FlutterEngine flutterEngine, @NonNull
    OnDeleteFileRequestPermissionListener onDeleteFileRequestPermission)
    {
        this.context = context;
        this.flutterEngine = flutterEngine;
        this.onDeleteFileRequestPermission = onDeleteFileRequestPermission;
        channel = new MethodChannel(flutterEngine.getDartExecutor()
                                            .getBinaryMessenger(), "fileControl");
        channel.setMethodCallHandler(this);
    }

    public void release()
    {
        channel.setMethodCallHandler(null);
    }

    @Override
    public void onMethodCall(@NonNull MethodCall call, @NonNull MethodChannel.Result result)
    {
        switch (call.method)
        {
            case "getPhotoList":
                onGetPhotoList(result);
                break;
            case "getVideoList":
                onGetVideoList(result);
                break;
            case "deleteFile":
                onDeleteFile(result, (String) call.arguments);
                break;
        }
    }

    private List<String> getMediaStoreFiles(Uri queryUri, String mimeType, String relativePath)
    {
        List<String> list = new ArrayList<>();
        String[] projection = new String[]{MediaStore.MediaColumns._ID,
                MediaStore.MediaColumns.DISPLAY_NAME, MediaStore.MediaColumns.MIME_TYPE,
                MediaStore.MediaColumns.DATA, MediaStore.MediaColumns.RELATIVE_PATH};
        //过滤mime类型
        String selection = MediaStore.MediaColumns.MIME_TYPE + "= ? AND " +
                MediaStore.MediaColumns.RELATIVE_PATH + "= ?";
        String[] selectionArgs = new String[]{mimeType, relativePath};
        String sortOrder = MediaStore.MediaColumns._ID + " DESC";
        try (Cursor cursor = context.getApplicationContext()
                .getContentResolver()
                .query(queryUri, projection, selection, selectionArgs, sortOrder))
        {
            if (cursor == null)
            {
                Log.d(TAG, "读取文件列表,但是cursor为null");
                return list;
            }
            int idIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID);
            int nameIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DISPLAY_NAME);
            int mimeIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.MIME_TYPE);
            int dataIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
            int relativePathIndex = cursor.getColumnIndexOrThrow(
                    MediaStore.MediaColumns.RELATIVE_PATH);
            while (cursor.moveToNext())
            {
                long id = cursor.getLong(idIndex);
                String name = cursor.getString(nameIndex);
                String mime = cursor.getString(mimeIndex);
                String data = cursor.getString(dataIndex);
                String rPath = cursor.getString(relativePathIndex);
                Log.d(TAG, "id=" + id + ", name=" + name + ", mime=" + mime + ", path=" + data +
                        ", relativePath=" + rPath);
                list.add(data);
            }
        }
        catch (Exception e)
        {
            Log.e(TAG, "读取文件列表异常", e);
        }
        return list;
    }

    /**
     * 读取照片列表
     *
     * @param result
     */
    private void onGetPhotoList(@NonNull MethodChannel.Result result)
    {
        /*new Thread(() -> {
            try
            {
                File dir = Utils.getPhotoDir(context);
                String rootPath = dir + File.separator;
                //时间戳是13位数字
                String[] list = dir.list((dir1, name) -> !name.startsWith(".") && name.endsWith(".jpg"));
                list = Arrays.stream(list)
                        .map(s -> rootPath + s)
                        .toArray(String[]::new);
                result.success(Arrays.asList(list));
            }
            catch (Exception e)
            {
                Log.e(TAG, "加载照片列表失败", e);
                result.error("100", "读取照片列表异常", e);
            }
        },"读取照片列表线程").start();*/

        new Thread(() -> {
            Uri uri = (Build.VERSION.SDK_INT >=
                    Build.VERSION_CODES.Q) ? MediaStore.Images.Media.getContentUri(
                    MediaStore.VOLUME_EXTERNAL_PRIMARY) : MediaStore.Images.Media.EXTERNAL_CONTENT_URI;

            List<String> list = getMediaStoreFiles(uri, "image/jpeg",
                                                   Utils.getPhotoMediaStoreRelativePath());
            result.success(list);
        }).start();
    }

    /**
     * 读取视频列表
     *
     * @param result
     */
    private void onGetVideoList(@NonNull MethodChannel.Result result)
    {
        /*new Thread(() -> {
            try
            {
                File dir = Utils.getRecordDir(context);
                String rootPath = dir + File.separator;
                //时间戳是13位数字
                String[] list = dir.list(
                        (dir1, name) -> !name.startsWith(".") && name.endsWith(".avi"));
                list = Arrays.stream(list)
                        .map(s -> rootPath + s)
                        .toArray(String[]::new);
                result.success(Arrays.asList(list));
            }
            catch (Exception e)
            {
                Log.e(TAG, "加载录像列表失败", e);
                result.error("200", "读取录像列表异常", e);
            }
        }, "读取视频列表线程").start();*/

        new Thread(() -> {
            Uri uri = (Build.VERSION.SDK_INT >=
                    Build.VERSION_CODES.Q) ? MediaStore.Video.Media.getContentUri(
                    MediaStore.VOLUME_EXTERNAL_PRIMARY) : MediaStore.Video.Media.EXTERNAL_CONTENT_URI;

            List<String> list = getMediaStoreFiles(uri, "video/avi",
                                                   Utils.getVideoMediaStoreRelativePath());
            result.success(list);
        }).start();
    }

    /**
     * 删除文件
     *
     * @param result
     * @param path
     */
    private void onDeleteFile(@NonNull MethodChannel.Result result, String path)
    {
        if (path == null || path.isEmpty() || !(path.endsWith(".jpg") || path.endsWith(".avi")))
        {
            result.error("301", "非图片或者视频文件", new Exception("非图片或者视频文件"));
            return;
        }
        new Thread(() -> {
            try
            {
                Log.d(TAG, "要删除的文件=" + path);
                //如果包含包名就表示是私有目录文件,直接删除
                if (path.contains(context.getPackageName()))
                {
                    File file = new File(path);
                    boolean bo = file.delete();
                    Log.e(TAG, "删除文件结果=" + bo);
                    result.success(null);
                    return;
                }

                boolean isJpg = path.endsWith(".jpg");

                String[] projection = new String[]{MediaStore.MediaColumns._ID,
                        MediaStore.MediaColumns.DATA};
                //过滤mime类型
                String selection = MediaStore.MediaColumns.MIME_TYPE + "= ? AND " +
                        MediaStore.MediaColumns.RELATIVE_PATH + "= ?";
                String[] selectionArgs = new String[]{isJpg ? "image/jpeg" : "video/avi",
                        isJpg ? Utils.getPhotoMediaStoreRelativePath() : Utils.getVideoMediaStoreRelativePath()};

                Uri contentUri;
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
                {
                    contentUri = isJpg ? MediaStore.Images.Media.getContentUri(
                            MediaStore.VOLUME_EXTERNAL_PRIMARY) : MediaStore.Video.Media.getContentUri(
                            MediaStore.VOLUME_EXTERNAL_PRIMARY);
                }
                else
                {
                    contentUri = isJpg ? MediaStore.Images.Media.EXTERNAL_CONTENT_URI : MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
                }
                //先根据绝对路径查出URI
                Uri uri = null;
                try (Cursor cursor = context.getApplicationContext()
                        .getContentResolver()
                        .query(contentUri, projection, selection, selectionArgs, null))
                {
                    if (cursor == null)
                    {
                        result.error("302", "文件不存在", new Exception("文件不存在"));
                        return;
                    }
                    int idIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns._ID);
                    int dataIndex = cursor.getColumnIndexOrThrow(MediaStore.MediaColumns.DATA);
                    while (cursor.moveToNext())
                    {
                        long id = cursor.getLong(idIndex);
                        String data = cursor.getString(dataIndex);
                        if (data.equals(path))
                        {
                            uri = ContentUris.withAppendedId(contentUri, id);
                            break;
                        }
                    }
                }
                catch (Exception e)
                {
                    Log.e(TAG, "读取照片列表异常", e);
                }
                if (uri == null)
                {
                    result.error("303", "文件不存在", new Exception("文件不存在"));
                    return;
                }
                //Q及以上有权限要求
                if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q)
                {
                    try
                    {
                        int deleted = context.getApplicationContext()
                                .getContentResolver()
                                .delete(uri, null, null);
                        Log.d(TAG, "删除的数量=" + deleted);
                        //有些设备即便删除成功了也会返回0,所以去掉判断
                        /*if (deleted <= 0)
                        {
                            result.error("304", "删除失败", new Exception("删除失败"));
                            return;
                        }*/
                        result.success(null);
                    }
                    //捕获权限异常,请求权限
                    catch (RecoverableSecurityException rse)
                    {
                        Log.d(TAG, "直接删除失败,请求权限");
                        tempDeleteFileResult = result;
                        tempDeleteFileUri = uri;
                        this.onDeleteFileRequestPermission.onDeleteFileRequestPermission(
                                rse.getUserAction()
                                        .getActionIntent()
                                        .getIntentSender());
                    }
                }
                else
                {
                    doDeleteFile(uri, result);
                }
            }
            catch (Exception e)
            {
                Log.e(TAG, "删除文件失败", e);
                result.error("300", "删除文件异常", e);
            }
        }, "删除文件线程").start();
    }

    /**
     * 权限删除文件
     *
     * @param canDelete 是否可以删除
     */
    public void onPermissionDeleteFile(boolean canDelete)
    {
        this.doDeleteFile(canDelete ? this.tempDeleteFileUri : null, this.tempDeleteFileResult);
        this.tempDeleteFileUri = null;
        this.tempDeleteFileResult = null;
    }

    /**
     * 执行删除文件动作
     *
     * @param uri    要通过ContentResolver删除文件的uri
     * @param result flutter结果
     */
    private void doDeleteFile(@Nullable Uri uri, @Nullable MethodChannel.Result result)
    {
        if (uri == null)
        {
            if (result != null)
            {
                result.error("306", "删除失败", new Exception("删除失败"));
            }
            return;
        }
        new Thread(() -> {
            try
            {
                int deleted = context.getApplicationContext()
                        .getContentResolver()
                        .delete(uri, null, null);
                Log.d(TAG, "删除的数量=" + deleted);
                //有些设备即便删除成功了也会返回0,所以去掉判断
                /*if (deleted <= 0)
                {
                    if (result != null)
                    {
                        result.error("304", "删除失败", new Exception("删除失败"));
                    }
                    return;
                }*/
                if (result != null)
                {
                    result.success(null);
                }
            }
            catch (Exception e)
            {
                Log.e(TAG, "执行删除动作异常", e);
                if (result != null)
                {
                    result.error("305", "执行删除动作异常", e);
                }
            }
        }).start();
    }
}
