package com.gh.gamecenter.common.utils;

import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.StatFs;
import android.os.StrictMode;
import android.provider.MediaStore;

import androidx.annotation.Nullable;

import org.json.JSONObject;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.UUID;

/**
 * @author guanchao wen
 * @email shuwoom.wgc@gmail.com
 * @modify hzh 2016/03/16
 * @update 2015-7-29下午2:26:02
 */
public class FileUtils {

    public static String getDownloadPath(Context context, String name) {
        return getDownloadDir(context) + File.separator + name;
    }

    public static String getDownloadDir(Context context) {
        String dir;
        String baseDir;
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.N) {
            try {
                // 在部分设备，可能是使用 sd 卡的设备？ getExternalFilesDir 方法返回 null
                // 异常时使用备用存储位置作为下载地址
                baseDir = context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
            } catch (NullPointerException exception) {
                if (Build.VERSION.SDK_INT == Build.VERSION_CODES.M) {
                    // Android 6.0 的设备无法直接下载至根目录 Download 文件夹（需要获取外部存储权限）
                    // 使用 getFilesDir 方法后，默认情况下 PackageInstaller 无法获取直接读取安装 APK
                    // 一般的处理方式是下载的时候将文件 openFileOutput(APK_FILENAME, Context.MODE_WORLD_READABLE)
                    // 但因为下载文件由下载模块创建，暂时不做修改，换成在下载完成后调用 file.setReadable(true, false) 使文件可读
                    baseDir = context.getFilesDir().getAbsolutePath();
                } else {
                    baseDir = Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath();
                }
            }
        } else {
            baseDir = context.getFilesDir().getAbsolutePath();
        }

        dir = checkDir(baseDir + File.separator + "gh-files");
        try {
            Runtime.getRuntime().exec("chmod 755 " + dir);
        } catch (IOException e) {
            e.printStackTrace();
        }
        return dir;
    }

    public static boolean isMounted() {
        return Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState());
    }

    private static String checkDir(String dir) {
        File directory = new File(dir);
        if (directory.exists() && !directory.isDirectory()) {
            directory.delete();
        }
        if (!directory.exists()) {
            directory.mkdirs();
        }
        return dir;
    }

    public static String getLogPath(Context context, String name) {
        return checkDir(getDir(context, "log")) + File.separator + name;
    }

    public static String getDir(Context context, String dir) {
        if (isMounted()) {
            // /storage/emulated/0/Android/data/包名/files
            File file = context.getExternalFilesDir(null);
            if (file != null) {
                return file.getAbsolutePath() + File.separator + dir;
            }
        }
        // /data/data/包名/files
        return context.getFilesDir().getAbsolutePath() + File.separator + dir;
    }

    public static String getPlatformPicDir(Context context) {
        return checkDir(getDir(context, "PlatformPic"));
    }

    public static void deleteFile(String savePath) {
        try {
            File file = new File(savePath);
            if (file.exists()) {
                file.delete();
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    public static void deleteFolder(File folder) {
        if (folder != null) {
            if (folder.isDirectory()) {
                for (File file : folder.listFiles()) {
                    if (file.isDirectory()) {
                        deleteFolder(file);
                    } else {
                        file.delete();
                    }
                }
            }
            folder.delete();
        }
    }

    public static boolean isEmptyFile(String path) {
        File file = new File(path);
        return !(file.exists() && file.length() != 0);
    }

    public static String isCanDownload(Context context, String size) {
        String msg = null;
        String packageSizeStr = "";
        for (int i = 0; i < size.length(); i++) {
            if ((size.charAt(i) >= 48 && size.charAt(i) <= 57) || size.charAt(i) == 46) {
                packageSizeStr += size.charAt(i);
            }
        }
        float packageSize = 0;
        if (packageSizeStr.length() != 0) {
            packageSize = Float.valueOf(packageSizeStr);
        }
        float freeSpace = getFreeSpaceByPath(getDownloadDir(context));
        if (freeSpace < packageSize) {
            msg = "手机存储空间不足，无法进行下载！";
        }
        return msg;
    }

    public static String isCanDownload(Context context, long size) {
        String msg = null;
        float freeSpace = getFreeSpaceByPath(getDownloadDir(context));
        if (freeSpace < size / 1024f / 1024f) {
            msg = "手机存储空间不足，无法进行下载！";
        }
        return msg;
    }

    // 返回剩余空间 单位MB
    @SuppressWarnings("deprecation")
    public static float getFreeSpaceByPath(String path) {
        // 部分用 SD卡的老手机会抛出   java.lang.IllegalArgumentException: Invalid path:  的异常
        // 出现这异常干脆返回 8192MB 让他下
        try {
            StatFs statfs = new StatFs(path);
            long blockSize = statfs.getBlockSize();
            long availableBlocks = statfs.getAvailableBlocks();

            return availableBlocks * blockSize / 1024f / 1024f;
        } catch (Exception e) {
            e.printStackTrace();
            return 8192;
        }
    }

    // 下载文件
    public static int downloadFile(String url, String savePath) {
        DataInputStream dis = null;
        FileOutputStream fos = null;
        try {
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(5 * 1000);
            connection.setReadTimeout(5 * 1000);
            connection.connect();
            int code = connection.getResponseCode();
            if (code == 200) {
                dis = new DataInputStream(connection.getInputStream());
                File file = new File(savePath);
                if (file.exists()) {
                    file.delete();
                }
                file.getParentFile().mkdir();
                file.createNewFile();
                fos = new FileOutputStream(file);
                byte[] buffer = new byte[1024];
                int len;
                while ((len = dis.read(buffer)) != -1) {
                    fos.write(buffer, 0, len);
                }
                fos.flush();
            }
            return code;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (dis != null) {
                try {
                    dis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return -1;
    }

    // 下载并更新文件 (与上面方法的不同之处是只有在下载完成以后才会更新旧文件)
    public static int downloadAndUpdateFile(String url, String savePath) {
        DataInputStream dis = null;
        FileOutputStream fos = null;
        try {
            String tempSavePath = savePath + ".tmp";

            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            connection.setRequestMethod("GET");
            connection.setConnectTimeout(5 * 1000);
            connection.setReadTimeout(5 * 1000);
            connection.connect();
            int code = connection.getResponseCode();
            if (code == 200) {
                dis = new DataInputStream(connection.getInputStream());
                File tempFile = new File(tempSavePath);
                if (tempFile.exists()) {
                    tempFile.delete();
                }
                tempFile.getParentFile().mkdir();
                tempFile.createNewFile();
                fos = new FileOutputStream(tempFile);
                byte[] buffer = new byte[1024];
                int len;
                while ((len = dis.read(buffer)) != -1) {
                    fos.write(buffer, 0, len);
                }
                fos.flush();

                File file = new File(savePath);
                if (file.exists()) {
                    file.delete();
                }

                tempFile.renameTo(file);
            }
            return code;
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (dis != null) {
                try {
                    dis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return -1;
    }

    // 上传文件
    public static JSONObject uploadFile(String url, String filePath, String token) {
        String end = "\r\n";
        String twoHyphens = "--";
        String boundary = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
        try {
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            /*
             * Output to the connection. Default is false, set to true because
             * post method must write something to the connection
             */
            connection.setDoOutput(true);
            // Read from the connection. Default is true.
            connection.setDoInput(true);
            // Post cannot use caches
            connection.setUseCaches(false);
            // Set the post method. Default is GET
            connection.setRequestMethod("POST");
            connection.setConnectTimeout(5 * 1000);
            connection.setReadTimeout(5 * 1000);
            // 设置请求属性
            connection.setRequestProperty("Connection", "Keep-Alive");
            connection.setRequestProperty("Charset", "UTF-8");
            connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
            if (token != null) {
                connection.setRequestProperty("TOKEN", token);
            }
            // 设置StrictMode 否则HTTPURLConnection连接失败，因为这是在主进程中进行网络连接
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectDiskReads().detectDiskWrites().detectNetwork()
                    .penaltyLog().build());
            File file = new File(filePath);
//            if (file.exists()) {
//                Utils.log("name = " + file.getName());
//                Utils.log("length = " + file.length());
//            }
            // 设置DataOutputStream，getOutputStream中默认调用connect()
            DataOutputStream dos = new DataOutputStream(connection.getOutputStream()); // output
            // to the connection
            dos.writeBytes(twoHyphens + boundary + end);
            dos.writeBytes("Content-Disposition: form-data; "
                    + "name=\"Filedata\";filename=\"" + file.getName() + "\"" + end);
            dos.writeBytes(end);
            // 取得文件的FileInputStream
            FileInputStream fStream = new FileInputStream(file);
            // 设置每次写入8192bytes
            int bufferSize = 8192;
            byte[] buffer = new byte[bufferSize]; // 8k
            int length;
            // 从文件读取数据至缓冲区
            while ((length = fStream.read(buffer)) != -1) {
                // 将资料写入DataOutputStream中
                dos.write(buffer, 0, length);
            }
            dos.writeBytes(end);
            dos.writeBytes(twoHyphens + boundary + twoHyphens + end);
            // 关闭流，写入的东西自动生成Http正文
            fStream.close();
            // 关闭DataOutputStream
            dos.flush();
            dos.close();

            InputStream inputStream;
            try {
                inputStream = connection.getInputStream();
            } catch (IOException ioe) {
                inputStream = connection.getErrorStream();
            }
            int ch;
            StringBuffer b = new StringBuffer();
            while ((ch = inputStream.read()) != -1) {
                b.append((char) ch);
            }
            // 显示网页响应内容
//            Utils.log("content = " + b.toString().trim());

            int statusCode = connection.getResponseCode();
//            Utils.log("statusCode = " + statusCode);
            JSONObject response = null;
            switch (statusCode) {
                case 200:
                    // {"icon":"http:\/\/gh-test-1.oss-cn-qingdao.aliyuncs.com\/pic\/57e4f4d58a3200042d29492f.jpg"}
                    response = new JSONObject(b.toString().trim());
                    response.put("statusCode", 200);
                    break;
                case 403:
                    response = new JSONObject(b.toString().trim());
                    response.put("statusCode", 403);
                    break;
                case 401:
                    response = new JSONObject();
                    response.put("statusCode", 401);
                    break;
            }

            return response;
        } catch (Exception e) {
            // 显示异常信息
            e.printStackTrace();
//            Utils.log("Fail:" + e);
        }
        return null;
    }


    // 上传文件 realPath:真实路径(防止对文件压缩后filePath路径改变) 提交成功后会返回该路径 以便识别上传文件的身份
    public static JSONObject uploadFile(String url, String filePath, String realPath, String token) {
        String end = "\r\n";
        String twoHyphens = "--";
        String boundary = UUID.randomUUID().toString().replaceAll("-", "").substring(0, 16);
        try {
            HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
            /*
             * Output to the connection. Default is false, set to true because
             * post method must write something to the connection
             */
            connection.setDoOutput(true);
            // Read from the connection. Default is true.
            connection.setDoInput(true);
            // Post cannot use caches
            connection.setUseCaches(false);
            // Set the post method. Default is GET
            connection.setRequestMethod("POST");
            connection.setConnectTimeout(5 * 1000);
            connection.setReadTimeout(5 * 1000);
            // 设置请求属性
            connection.setRequestProperty("Connection", "Keep-Alive");
            connection.setRequestProperty("Charset", "UTF-8");
            connection.setRequestProperty("Content-Type", "multipart/form-data;boundary=" + boundary);
            if (token != null) {
                connection.setRequestProperty("TOKEN", token);
            }
            // 设置StrictMode 否则HTTPURLConnection连接失败，因为这是在主进程中进行网络连接
            StrictMode.setThreadPolicy(new StrictMode.ThreadPolicy.Builder()
                    .detectDiskReads().detectDiskWrites().detectNetwork()
                    .penaltyLog().build());
            File file = new File(filePath);
//            if (file.exists()) {
//                Utils.log("name = " + file.getName());
//                Utils.log("length = " + file.length());
//            }
            // 设置DataOutputStream，getOutputStream中默认调用connect()
            DataOutputStream dos = new DataOutputStream(connection.getOutputStream()); // output
            // to the connection
            dos.writeBytes(twoHyphens + boundary + end);
            dos.writeBytes("Content-Disposition: form-data; "
                    + "name=\"Filedata\";filename=\"" + file.getName() + "\"" + end);
            dos.writeBytes(end);
            // 取得文件的FileInputStream
            FileInputStream fStream = new FileInputStream(file);
            // 设置每次写入8192bytes
            int bufferSize = 8192;
            byte[] buffer = new byte[bufferSize]; // 8k
            int length;
            // 从文件读取数据至缓冲区
            while ((length = fStream.read(buffer)) != -1) {
                // 将资料写入DataOutputStream中
                dos.write(buffer, 0, length);
            }
            dos.writeBytes(end);
            dos.writeBytes(twoHyphens + boundary + twoHyphens + end);
            // 关闭流，写入的东西自动生成Http正文
            fStream.close();
            // 关闭DataOutputStream
            dos.flush();
            dos.close();

            InputStream inputStream;
            try {
                inputStream = connection.getInputStream();
            } catch (IOException ioe) {
                inputStream = connection.getErrorStream();
            }
            int ch;
            StringBuffer b = new StringBuffer();
            while ((ch = inputStream.read()) != -1) {
                b.append((char) ch);
            }
            // 显示网页响应内容
//            Utils.log("content = " + b.toString().trim());

            int statusCode = connection.getResponseCode();
//            Utils.log("statusCode = " + statusCode);
            JSONObject response = null;
            switch (statusCode) {
                case 200:
                    // {"icon":"http:\/\/gh-test-1.oss-cn-qingdao.aliyuncs.com\/pic\/57e4f4d58a3200042d29492f.jpg"}
                    response = new JSONObject(b.toString().trim());
                    response.put("statusCode", 200);
                    response.put("realPath", realPath);
                    break;
                case 403:
                    response = new JSONObject(b.toString().trim());
                    response.put("statusCode", 403);
                    response.put("realPath", realPath);
                    break;
                case 401:
                    response = new JSONObject();
                    response.put("statusCode", 401);
                    break;
            }

            return response;
        } catch (Exception e) {
            // 显示异常信息
            e.printStackTrace();
//            Utils.log("Fail:" + e);
        }
        return null;
    }


    // 读取文件，返回byte[]
    public static byte[] readFile(File file) {
        if (file == null) {
            return null;
        }
        FileInputStream fis = null;
        ByteArrayOutputStream bos = null;
        try {
            fis = new FileInputStream(file);
            bos = new ByteArrayOutputStream();
            byte[] buffer = new byte[2048];
            int len;
            while ((len = fis.read(buffer)) != -1) {
                bos.write(buffer, 0, len);
            }
            bos.flush();
            return bos.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (fis != null) {
                try {
                    fis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (bos != null) {
                try {
                    bos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return null;
    }

    // 根据byte[]，保存文件
    public static void saveFile(File file, byte[] data) {
        if (file == null || data == null) {
            return;
        }
        ByteArrayInputStream bis = null;
        FileOutputStream fos = null;
        try {
            bis = new ByteArrayInputStream(data);
            fos = new FileOutputStream(file);
            byte[] buffer = new byte[2048];
            int len;
            while ((len = bis.read(buffer)) != -1) {
                fos.write(buffer, 0, len);
            }
            fos.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            if (bis != null) {
                try {
                    bis.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            if (fos != null) {
                try {
                    fos.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    /**
     * @param context  suggestion application context
     * @param filePath file path
     * @return A MIME type for the content {category}/{type}
     * example: video/mp4
     */
    @Nullable
    public static String getFileMimeType(Context context, String filePath) {
        Uri contentUri = getFileContentUri(context, filePath);
        if (contentUri != null) {
            return context.getContentResolver().getType(contentUri);
        }
        return null;
    }

    @Nullable
    public static Uri getFileContentUri(Context context, String filePath) {
        Cursor cursor = null;
        try {
            String absolutePath = new File(filePath).getAbsolutePath();
            cursor = context.getContentResolver().query(
                    MediaStore.Files.getContentUri("external"),
                    new String[]{MediaStore.Files.FileColumns._ID},
                    MediaStore.Files.FileColumns.DATA + "=? ",
                    new String[]{absolutePath}, null);
            if (cursor != null && cursor.moveToFirst()) {
                int id = cursor.getInt(cursor.getColumnIndex(MediaStore.MediaColumns._ID));
                cursor.close();
                return Uri.withAppendedPath(MediaStore.Files.getContentUri("external"), "" + id);
            } else return null;
        } catch (Exception ignore) {
        } finally {
            if (cursor != null) cursor.close();
        }
        return null;
    }
}
