package de.sebse.fuplanner.fragments.moddetails;


import android.Manifest;
import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Environment;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;

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

import androidx.annotation.NonNull;
import androidx.core.app.ActivityCompat;
import androidx.fragment.app.Fragment;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;
import androidx.swiperefreshlayout.widget.SwipeRefreshLayout;
import de.sebse.fuplanner.MainActivity;
import de.sebse.fuplanner.R;
import de.sebse.fuplanner.services.KVV.KVV;
import de.sebse.fuplanner.services.KVV.types.Modules;
import de.sebse.fuplanner.services.KVV.types.Resource;
import de.sebse.fuplanner.tools.MainActivityListener;
import de.sebse.fuplanner.tools.Regex;
import de.sebse.fuplanner.tools.UtilsDate;
import de.sebse.fuplanner.tools.logging.Logger;
import de.sebse.fuplanner.tools.ui.treeview.DirectoryNodeBinder;
import de.sebse.fuplanner.tools.ui.treeview.FileNodeBinder;
import de.sebse.fuplanner.tools.ui.treeview.TreeNode;
import de.sebse.fuplanner.tools.ui.treeview.TreeViewAdapter;

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

/**
 * A simple {@link Fragment} subclass.
 * Use the {@link ModDetailResourceFragment#newInstance} factory method to
 * create an instance of this fragment.
 */
public class ModDetailResourceFragment extends Fragment {
    private static final String ARG_POSITION = "itemPosition";

    private String mItemPos;
    private final Logger log = new Logger(this);
    private ModDetailResourceAdapter adapter;
    private SwipeRefreshLayout swipeLayout;
    private MainActivityListener context;
    private RequestedDownload requestedDownload;


    public ModDetailResourceFragment() {
        // Required empty public constructor
    }

    /**
     * Use this factory method to create a new instance of
     * this fragment using the provided parameters.
     *
     * @param itemPosition Item position in module list.
     * @return A new instance of fragment ModDetailAnnounceFragment.
     */
    public static ModDetailResourceFragment newInstance(String itemPosition) {
        ModDetailResourceFragment fragment = new ModDetailResourceFragment();
        Bundle args = new Bundle();
        args.putString(ARG_POSITION, itemPosition);
        fragment.setArguments(args);
        return fragment;
    }

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        if (getArguments() != null) {
            mItemPos = getArguments().getString(ARG_POSITION);
        }
    }

    @Override
    public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
                             Bundle savedInstanceState) {
        // Inflate the layout for this fragment
        View view = inflater.inflate(R.layout.fragment_recycler_view, container, false);
        // Set the adapter
        Context context = view.getContext();
        RecyclerView recyclerView = view.findViewById(R.id.list);
        recyclerView.setLayoutManager(new LinearLayoutManager(context));

        adapter = new ModDetailResourceAdapter(Arrays.asList(new FileNodeBinder(), new DirectoryNodeBinder()));
        adapter.setOnTreeNodeListener(new TreeViewAdapter.OnTreeNodeListener() {
            @Override
            public boolean onClick(TreeNode node, RecyclerView.ViewHolder holder) {
                if (!node.isLeaf()) {
                    // Update and toggle the node.
                    onToggle(!node.isExpand(), holder);
                } else if(node.getContent() instanceof Resource.File) { // if leaf is file
                    KVV kvv = ModDetailResourceFragment.this.context.getKVV();
                    kvv.getModule(mItemPos, (Modules.Module module) -> {
                        if (getContext() == null)
                            return;
                        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getContext());
                        Resource.File file = (Resource.File) node.getContent();
                        String folderName = "FU-"+module.title.replaceAll("[:*<>|/\"\\\\]", "-");
                        File f = new File(Environment.getExternalStoragePublicDirectory(
                                Environment.DIRECTORY_DOWNLOADS)+"/"+folderName+"/"+file.getTitle());
                        alertDialogBuilder
                                .setTitle(file.getTitle())
                                .setMessage(
                                        getResources().getString(R.string.creator_name, file.getAuthor()) + "\n" +
                                        getResources().getString(R.string.last_modified_on, UtilsDate.getModifiedDateTime(context, file.getModifiedDate()))
                                )
                                .setCancelable(true)
                                .setNeutralButton(R.string.close, (dialog, id) -> dialog.cancel())
                                .setPositiveButton(R.string.download, (dialog, id) -> download(file, folderName, true));
                        // if already downloaded, show open button
                        if (f.exists()) {
                            alertDialogBuilder
                                    .setNegativeButton(R.string.openFile, (dialog, id) -> download(file, folderName, false));
                        }
                        AlertDialog alertDialog = alertDialogBuilder.create();
                        alertDialog.show();

                    }, log::e);
                }
                return false;
            }

            @Override
            public void onToggle(boolean isExpand, RecyclerView.ViewHolder holder) {
                DirectoryNodeBinder.ViewHolder dirViewHolder = (DirectoryNodeBinder.ViewHolder) holder;
                final ImageView ivArrow = dirViewHolder.getIvArrow();
                int rotateDegree = isExpand ? 90 : -90;
                ivArrow.animate().rotationBy(rotateDegree).start();
            }
        });

        recyclerView.setAdapter(adapter);

        // Getting SwipeContainerLayout
        swipeLayout = view.findViewById(R.id.swipe_container);
        // Adding Listener
        swipeLayout.setOnRefreshListener(() -> refresh(true));
        refresh(false);

        return view;
    }

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

    private void downloadOrOpen(Resource.File file, String folderName, boolean downloadNew) {
        KVV kvv = this.context.getKVV();
        if(isExternalStorageWritable()){
            kvv.getResourceFile(success1 -> {
                // Downloading file failed
                if (success1.equals("")){
                    showDownloadError();
                }else {
                    if (Regex.has("^http", success1)){
                        Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(success1));
                        startActivity(intent);
                    }
                    else {
                        fileOpen(new File(success1));
                    }

                }
            }, log::e, file.getTitle(), file.getUrl(), folderName, downloadNew);
        }
    }

    private void showDownloadError() {
        AlertDialog.Builder alertDialogBuilder = new AlertDialog.Builder(getContext());
        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();
    }

    @Override
    public void onAttach(Context context) {
        super.onAttach(context);
        if (context instanceof MainActivityListener) {
            this.context = ((MainActivityListener) context);
            this.context.addRequestPermissionsResultListener((requestCode, permissions, grantResults) -> {
                if (requestedDownload == null) {
                    log.d("No request");
                    return;
                }
                if (getActivity() == null) {
                    showDownloadError();
                    return;
                }
                ArrayList<Integer> intList = new ArrayList<>();
                for (int i : grantResults)
                {
                    intList.add(i);
                }
                log.d(requestCode, Arrays.asList(permissions), intList);
                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 {
                        log.d(requestedDownload, pos, grantResults[pos]);
                        showDownloadError();
                    }
                    requestedDownload = null;
                }
            }, "ModDetailResourceFragment");
        } else
            throw new RuntimeException(context.toString() + " must implement MainActivityListener");
    }

    @Override
    public void onDetach() {
        super.onDetach();
        this.context.removeRequestPermissionsResultListener("ModDetailResourceFragment");
    }

    /* 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){
        Uri uri = Uri.fromFile(url);

        Intent intent = new Intent();//Intent.ACTION_VIEW
        // 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);
        startActivity(intent);

    }

    private void refresh(boolean forceRefresh) {
        if (getActivity() != null) {
            KVV kvv = ((MainActivity) getActivity()).getKVV();
            kvv.getModule(mItemPos, (Modules.Module module) -> {
                adapter.setModule(module);
                kvv.getModuleResources(module, success1 -> {
                    adapter.setModule();
                    swipeLayout.setRefreshing(false);
                }, error -> {
                    swipeLayout.setRefreshing(false);
                    log.e(error);
                }, forceRefresh);
            }, error -> {
                swipeLayout.setRefreshing(false);
                log.e(error);
            }, forceRefresh);
        }
    }





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

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