package com.tyron.code.util;

import android.annotation.SuppressLint;
import android.content.ContentUris;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.provider.DocumentsContract;
import android.provider.MediaStore;
import android.provider.OpenableColumns;
import android.text.TextUtils;
import android.util.Log;
import com.tyron.code.ApplicationLoader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.InputStream;

public class FileUtils {
  private static Uri contentUri = null;

  @SuppressLint("NewApi")
  public static String getPath(final Uri uri) {
    // check here to KITKAT or new version
    final boolean isKitKat = true;
    String selection = null;
    String[] selectionArgs = null;
    // DocumentProvider
    if (isKitKat) {
      // ExternalStorageProvider

      if (isExternalStorageDocument(uri)) {
        final String docId = DocumentsContract.getDocumentId(uri);
        final String[] split = docId.split(":");
        final String type = split[0];

        String fullPath = getPathFromExtSD(split);
        if (fullPath != "") {
          return fullPath;
        } else {
          return null;
        }
      }

      // DownloadsProvider

      if (isDownloadsDocument(uri)) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
          final String id;
          Cursor cursor = null;
          try {
            cursor =
                ApplicationLoader.applicationContext
                    .getContentResolver()
                    .query(
                        uri, new String[] {MediaStore.MediaColumns.DISPLAY_NAME}, null, null, null);
            if (cursor != null && cursor.moveToFirst()) {
              String fileName = cursor.getString(0);
              String path =
                  Environment.getExternalStorageDirectory().toString() + "/Download/" + fileName;
              if (!TextUtils.isEmpty(path)) {
                return path;
              }
            }
          } finally {
            if (cursor != null) cursor.close();
          }
          id = DocumentsContract.getDocumentId(uri);
          if (!TextUtils.isEmpty(id)) {
            if (id.startsWith("raw:")) {
              return id.replaceFirst("raw:", "");
            }
            String[] contentUriPrefixesToTry =
                new String[] {
                  "content://downloads/public_downloads", "content://downloads/my_downloads"
                };
            for (String contentUriPrefix : contentUriPrefixesToTry) {
              try {
                final Uri contentUri =
                    ContentUris.withAppendedId(Uri.parse(contentUriPrefix), Long.valueOf(id));

                return getDataColumn(ApplicationLoader.applicationContext, contentUri, null, null);
              } catch (NumberFormatException e) {
                // In Android 8 and Android P the id is not a number
                return uri.getPath().replaceFirst("^/document/raw:", "").replaceFirst("^raw:", "");
              }
            }
          }
        } else {
          final String id = DocumentsContract.getDocumentId(uri);

          if (id.startsWith("raw:")) {
            return id.replaceFirst("raw:", "");
          }
          try {
            contentUri =
                ContentUris.withAppendedId(
                    Uri.parse("content://downloads/public_downloads"), Long.parseLong(id));
          } catch (NumberFormatException e) {
            e.printStackTrace();
          }
          if (contentUri != null) {

            return getDataColumn(ApplicationLoader.applicationContext, contentUri, null, null);
          }
        }
      }

      // MediaProvider
      if (isMediaDocument(uri)) {
        final String docId = DocumentsContract.getDocumentId(uri);
        final String[] split = docId.split(":");
        final String type = split[0];

        Uri contentUri = null;

        if ("image".equals(type)) {
          contentUri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
        } else if ("video".equals(type)) {
          contentUri = MediaStore.Video.Media.EXTERNAL_CONTENT_URI;
        } else if ("audio".equals(type)) {
          contentUri = MediaStore.Audio.Media.EXTERNAL_CONTENT_URI;
        }
        selection = "_id=?";
        selectionArgs = new String[] {split[1]};

        return getDataColumn(
            ApplicationLoader.applicationContext, contentUri, selection, selectionArgs);
      }

      if (isGoogleDriveUri(uri)) {
        return getDriveFilePath(uri);
      }

      if (isWhatsAppFile(uri)) {
        return getFilePathForWhatsApp(uri);
      }

      if ("content".equalsIgnoreCase(uri.getScheme())) {

        if (isGooglePhotosUri(uri)) {
          return uri.getLastPathSegment();
        }
        if (isGoogleDriveUri(uri)) {
          return getDriveFilePath(uri);
        }
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {

          // return getFilePathFromURI(context,uri);
          return copyFileToInternalStorage(uri, "userfiles");
          // return getRealPathFromURI(context,uri);
        } else {
          return getDataColumn(ApplicationLoader.applicationContext, uri, null, null);
        }
      }
      if ("file".equalsIgnoreCase(uri.getScheme())) {
        return uri.getPath();
      }
    } else {

      if (isWhatsAppFile(uri)) {
        return getFilePathForWhatsApp(uri);
      }

      if ("content".equalsIgnoreCase(uri.getScheme())) {
        String[] projection = {MediaStore.Images.Media.DATA};
        Cursor cursor = null;
        try {
          cursor =
              ApplicationLoader.applicationContext
                  .getContentResolver()
                  .query(uri, projection, selection, selectionArgs, null);
          int column_index = cursor.getColumnIndexOrThrow(MediaStore.Images.Media.DATA);
          if (cursor.moveToFirst()) {
            return cursor.getString(column_index);
          }
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    }

    return null;
  }

  private static boolean fileExists(String filePath) {
    File file = new File(filePath);

    return file.exists();
  }

  private static String getPathFromExtSD(String[] pathData) {
    final String type = pathData[0];
    final String relativePath = "/" + pathData[1];
    String fullPath = "";

    // on my Sony devices (4.4.4 & 5.1.1), `type` is a dynamic string
    // something like "71F8-2C0A", some kind of unique id per storage
    // don't know any API that can get the root path of that storage based on its id.
    //
    // so no "primary" type, but let the check here for other devices
    if ("primary".equalsIgnoreCase(type)) {
      fullPath = Environment.getExternalStorageDirectory() + relativePath;
      if (fileExists(fullPath)) {
        return fullPath;
      }
    }

    // Environment.isExternalStorageRemovable() is `true` for external and internal storage
    // so we cannot relay on it.
    //
    // instead, for each possible path, check if file exists
    // we'll start with secondary storage as this could be our (physically) removable sd card
    fullPath = System.getenv("SECONDARY_STORAGE") + relativePath;
    if (fileExists(fullPath)) {
      return fullPath;
    }

    fullPath = System.getenv("EXTERNAL_STORAGE") + relativePath;
    if (fileExists(fullPath)) {
      return fullPath;
    }

    return fullPath;
  }

  private static String getDriveFilePath(Uri uri) {
    Uri returnUri = uri;
    Cursor returnCursor =
        ApplicationLoader.applicationContext
            .getContentResolver()
            .query(returnUri, null, null, null, null);
    /*
     * Get the column indexes of the data in the Cursor,
     *     * move to the first row in the Cursor, get the data,
     *     * and display it.
     * */
    int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
    int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
    returnCursor.moveToFirst();
    String name = (returnCursor.getString(nameIndex));
    String size = (Long.toString(returnCursor.getLong(sizeIndex)));
    File file = new File(ApplicationLoader.applicationContext.getCacheDir(), name);
    try {
      InputStream inputStream =
          ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri);
      FileOutputStream outputStream = new FileOutputStream(file);
      int read = 0;
      int maxBufferSize = 1024 * 1024;
      int bytesAvailable = inputStream.available();

      // int bufferSize = 1024;
      int bufferSize = Math.min(bytesAvailable, maxBufferSize);

      final byte[] buffers = new byte[bufferSize];
      while ((read = inputStream.read(buffers)) != -1) {
        outputStream.write(buffers, 0, read);
      }
      Log.e("File Size", "Size " + file.length());
      inputStream.close();
      outputStream.close();
      Log.e("File Path", "Path " + file.getPath());
      Log.e("File Size", "Size " + file.length());
    } catch (Exception e) {
      Log.e("Exception", e.getMessage());
    }
    return file.getPath();
  }

  /***
   * Used for Android Q+
   * @param uri
   * @param newDirName if you want to create a directory, you can set this variable
   * @return
   */
  private static String copyFileToInternalStorage(Uri uri, String newDirName) {
    Uri returnUri = uri;

    Cursor returnCursor =
        ApplicationLoader.applicationContext
            .getContentResolver()
            .query(
                returnUri,
                new String[] {OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE},
                null,
                null,
                null);

    /*
     * Get the column indexes of the data in the Cursor,
     *     * move to the first row in the Cursor, get the data,
     *     * and display it.
     * */
    int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME);
    int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE);
    returnCursor.moveToFirst();
    String name = (returnCursor.getString(nameIndex));
    String size = (Long.toString(returnCursor.getLong(sizeIndex)));

    File output;
    if (!newDirName.equals("")) {
      File dir = new File(ApplicationLoader.applicationContext.getFilesDir() + "/" + newDirName);
      if (!dir.exists()) {
        dir.mkdir();
      }
      output =
          new File(
              ApplicationLoader.applicationContext.getFilesDir() + "/" + newDirName + "/" + name);
    } else {
      output = new File(ApplicationLoader.applicationContext.getFilesDir() + "/" + name);
    }
    try {
      InputStream inputStream =
          ApplicationLoader.applicationContext.getContentResolver().openInputStream(uri);
      FileOutputStream outputStream = new FileOutputStream(output);
      int read = 0;
      int bufferSize = 1024;
      final byte[] buffers = new byte[bufferSize];
      while ((read = inputStream.read(buffers)) != -1) {
        outputStream.write(buffers, 0, read);
      }

      inputStream.close();
      outputStream.close();

    } catch (Exception e) {

      Log.e("Exception", e.getMessage());
    }

    return output.getPath();
  }

  private static String getFilePathForWhatsApp(Uri uri) {
    return copyFileToInternalStorage(uri, "whatsapp");
  }

  private static String getDataColumn(
      Context context, Uri uri, String selection, String[] selectionArgs) {
    Cursor cursor = null;
    final String column = "_data";
    final String[] projection = {column};

    try {
      cursor = context.getContentResolver().query(uri, projection, selection, selectionArgs, null);

      if (cursor != null && cursor.moveToFirst()) {
        final int index = cursor.getColumnIndexOrThrow(column);
        return cursor.getString(index);
      }
    } finally {
      if (cursor != null) cursor.close();
    }

    return null;
  }

  private static boolean isExternalStorageDocument(Uri uri) {
    return "com.android.externalstorage.documents".equals(uri.getAuthority());
  }

  private static boolean isDownloadsDocument(Uri uri) {
    return "com.android.providers.downloads.documents".equals(uri.getAuthority());
  }

  private static boolean isMediaDocument(Uri uri) {
    return "com.android.providers.media.documents".equals(uri.getAuthority());
  }

  private static boolean isGooglePhotosUri(Uri uri) {
    return "com.google.android.apps.photos.content".equals(uri.getAuthority());
  }

  public static boolean isWhatsAppFile(Uri uri) {
    return "com.whatsapp.provider.media".equals(uri.getAuthority());
  }

  private static boolean isGoogleDriveUri(Uri uri) {
    return "com.google.android.apps.docs.storage".equals(uri.getAuthority())
        || "com.google.android.apps.docs.storage.legacy".equals(uri.getAuthority());
  }
}
