package de.sebse.fuplanner.services.kvv.ui;

import android.Manifest;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.res.Resources;
import android.net.Uri;
import android.os.Environment;

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

import androidx.annotation.Nullable;
import androidx.core.app.ActivityCompat;
import androidx.core.content.FileProvider;
import de.sebse.fuplanner.MainActivity;
import de.sebse.fuplanner.R;
import de.sebse.fuplanner.services.kvv.types.Resource;
import de.sebse.fuplanner.tools.Regex;
import de.sebse.fuplanner.tools.RequestPermissionsResultListener;
import de.sebse.fuplanner.tools.UtilsDate;
import de.sebse.fuplanner.tools.logging.Logger;

import static androidx.core.content.ContextCompat.checkSelfPermission;

public class Download {

    private final ContextInterface contextInterface;
    private final ActivityInterface activityInterface;
    private RequestedDownload requestedDownload;
    private final Logger log = new Logger(this);


    public Download(ContextInterface contextInterface, ActivityInterface activityInterface) {
        this.contextInterface = contextInterface;
        this.activityInterface = activityInterface;
    }

    public void openDownloadDialog(String title, String url, String folderName) {
        openDownloadDialog(new Resource.File("", title, 0, url, true, "", ""), folderName);
    }

    public void openDownloadDialog(Resource.File file, String folderName) {
        Context context = contextInterface.get();
        if (context == null)
            return;
        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
        File f = new File(Environment.getExternalStoragePublicDirectory(
                Environment.DIRECTORY_DOWNLOADS)+"/"+folderName+"/"+file.getTitle());
        Resources resources = context.getResources();
        String message = "";
        if (file.getAuthor() != null && !file.getAuthor().isEmpty())
            message += resources.getString(R.string.creator_name, file.getAuthor());
        if (file.getModifiedDate() != 0) {
            if (!message.isEmpty())
                message += "\n";
            message += resources.getString(R.string.last_modified_on, UtilsDate.getModifiedDateTime(context, file.getModifiedDate()));
        }

        alertDialogBuilder
                .setTitle(file.getTitle())
                .setMessage(message)
                .setCancelable(true)
                .setNeutralButton(R.string.close, (dialog, id) -> dialog.cancel());
        // if already downloaded, show open button
        if (f.exists()) {
            alertDialogBuilder
                    .setPositiveButton(R.string.download_again, (dialog, id) -> download(file, folderName, true))
                    .setNegativeButton(R.string.openFile, (dialog, id) -> download(file, folderName, false));
        } else {
            alertDialogBuilder
                    .setPositiveButton(R.string.download, (dialog, id) -> download(file, folderName, true));
        }
        AlertDialog alertDialog = alertDialogBuilder.create();
        alertDialog.show();
    }

    private void download(Resource.File file, String folderName, boolean downloadNew){
        MainActivity activity = activityInterface.get();
        if (activity == null) {
            showDownloadError();
            return;
        }
        if (checkSelfPermission(activity, Manifest.permission.WRITE_EXTERNAL_STORAGE) == PackageManager.PERMISSION_GRANTED) {
            // Access granted
            downloadOrOpen(file, folderName, downloadNew);
        } else {
            this.requestedDownload = new RequestedDownload(file, folderName, downloadNew);
            ActivityCompat.requestPermissions(activity,
                    new String[]{Manifest.permission.WRITE_EXTERNAL_STORAGE},
                    1);
        }
    }

    private void downloadOrOpen(Resource.File file, String folderName, boolean downloadNew) {
        if (!isExternalStorageWritable()) {
            return;
        }
        MainActivity activity = activityInterface.get();
        if (activity == null) {
            showDownloadError();
            return;
        }
        activity.getKVV().modules().resources().file(file.getTitle(), file.getUrl(), folderName, success -> {
            Context context = contextInterface.get();
            if (success.equals("") || context== null) {
                showDownloadError();
            } else {
                if (Regex.has("^http", success)){
                    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(success));
                    context.startActivity(intent);
                }
                else {
                    fileOpen(new File(success));
                }
            }
        }, log::e, downloadNew);
    }

    private void showDownloadError() {
        Context context = contextInterface.get();
        if (context == null)
            return;
        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(context);
        alertDialogBuilder
                .setTitle(R.string.ErrorFileDownload)
                .setMessage(
                        R.string.ErrorFileDownloadText
                )
                .setCancelable(true)
                .setNeutralButton(R.string.close, (dialog, id) -> dialog.cancel());
        AlertDialog alertDialog = alertDialogBuilder.create();
        alertDialog.show();
    }

    public RequestPermissionsResultListener getRequestPermissionsResultListener() {
        return (requestCode, permissions, grantResults) -> {
            if (requestedDownload == null) {
                log.e("No request");
                return;
            }
            if (activityInterface.get() == null) {
                showDownloadError();
                return;
            }
            ArrayList<Integer> intList = new ArrayList<>();
            for (int i : grantResults)
            {
                intList.add(i);
            }
            int pos = Arrays.asList(permissions).indexOf("android.permission.WRITE_EXTERNAL_STORAGE");
            if (pos != -1) {
                if (grantResults[pos] != -1) {
                    downloadOrOpen(requestedDownload.file, requestedDownload.folderName, requestedDownload.downloadNew);
                } else {
                    showDownloadError();
                }
                requestedDownload = null;
            }
        };
    }

    private class RequestedDownload {
        final Resource.File file;
        final String folderName;
        final boolean downloadNew;

        RequestedDownload(Resource.File file, String folderName, boolean downloadNew) {
            this.file = file;
            this.folderName = folderName;
            this.downloadNew = downloadNew;
        }
    }

    /* Checks if external storage is available for read and write */
    private boolean isExternalStorageWritable() {
        String state = Environment.getExternalStorageState();
        if (Environment.MEDIA_MOUNTED.equals(state)) {
            return true;
        }
        log.e("File system: Writing not possible");
        return false;
    }

    private void fileOpen(File url){
        Context context = contextInterface.get();
        if (context == null)
            return;
        Uri uri = FileProvider.getUriForFile(context, context.getApplicationContext().getPackageName() + ".my.provider", url);

        Intent intent;
        if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.KITKAT) {
            intent = new Intent(Intent.ACTION_VIEW);
        } else {
            intent = new Intent();
        }
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
        // Check what kind of file you are trying to open, by comparing the url with extensions.
        // When the if condition is matched, plugin sets the correct intent (mime) type,
        // so Android knew what application to use to open the file
        if (url.toString().contains(".doc") || url.toString().contains(".docx")) {
            // Word document
            intent.setDataAndType(uri, "application/msword");
        } else if(url.toString().contains(".pdf")) {
            // PDF file
            intent.setDataAndType(uri, "application/pdf");
        } else if(url.toString().contains(".ppt") || url.toString().contains(".pptx")) {
            // Powerpoint file
            intent.setDataAndType(uri, "application/vnd.ms-powerpoint");
        } else if(url.toString().contains(".xls") || url.toString().contains(".xlsx")) {
            // Excel file
            intent.setDataAndType(uri, "application/vnd.ms-excel");
        } else if(url.toString().contains(".zip") || url.toString().contains(".rar")) {
            // ZIP file
            intent.setDataAndType(uri, "application/zip");
        } else if(url.toString().contains(".rtf")) {
            // RTF file
            intent.setDataAndType(uri, "application/rtf");
        } else if(url.toString().contains(".wav") || url.toString().contains(".mp3")) {
            // WAV audio file
            intent.setDataAndType(uri, "audio/x-wav");
        } else if(url.toString().contains(".gif")) {
            // GIF file
            intent.setDataAndType(uri, "image/gif");
        } else if(url.toString().contains(".jpg") || url.toString().contains(".jpeg") || url.toString().contains(".png")) {
            // JPG file
            intent.setDataAndType(uri, "image/jpeg");
        } else if(url.toString().contains(".txt")) {
            // Text file
            intent.setDataAndType(uri, "text/plain");
        } else if(url.toString().contains(".3gp") || url.toString().contains(".mpg") || url.toString().contains(".mpeg") || url.toString().contains(".mpe") || url.toString().contains(".mp4") || url.toString().contains(".avi")) {
            // Video files
            intent.setDataAndType(uri, "video/*");
        } else {
            //if you want you can also define the intent type for any other file

            //additionally use else clause below, to manage other unknown extensions
            //in this case, Android will show all applications installed on the device
            //so you can choose which application to use
            intent.setDataAndType(uri, "*/*");
        }
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        context.startActivity(intent);

    }

    @FunctionalInterface
    public interface ContextInterface {
        @Nullable Context get();
    }

    @FunctionalInterface
    public interface ActivityInterface {
        @Nullable MainActivity get();
    }

    public interface OnDownloadRequestInterface {
        void request(String title, String url);
    }
}
