package com.stevesoltys.backup.activity;

import android.app.Activity;
import android.app.job.JobInfo;
import android.app.job.JobScheduler;
import android.content.ActivityNotFoundException;
import android.content.ComponentName;
import android.content.ContentResolver;
import android.content.Intent;
import android.net.Uri;
import android.util.Log;
import android.widget.Toast;

import com.stevesoltys.backup.activity.backup.CreateBackupActivity;
import com.stevesoltys.backup.activity.restore.RestoreBackupActivity;
import com.stevesoltys.backup.service.backup.BackupJobService;
import com.stevesoltys.backup.transport.ConfigurableBackupTransportService;

import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.Date;
import java.util.Locale;

import static android.app.job.JobInfo.NETWORK_TYPE_UNMETERED;
import static android.content.Intent.ACTION_OPEN_DOCUMENT;
import static android.content.Intent.ACTION_OPEN_DOCUMENT_TREE;
import static android.content.Intent.CATEGORY_OPENABLE;
import static android.content.Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION;
import static android.content.Intent.FLAG_GRANT_READ_URI_PERMISSION;
import static android.content.Intent.FLAG_GRANT_WRITE_URI_PERMISSION;
import static android.provider.DocumentsContract.buildDocumentUriUsingTree;
import static android.provider.DocumentsContract.createDocument;
import static android.provider.DocumentsContract.getTreeDocumentId;
import static com.stevesoltys.backup.Backup.JOB_ID_BACKGROUND_BACKUP;
import static com.stevesoltys.backup.activity.MainActivity.OPEN_DOCUMENT_TREE_BACKUP_REQUEST_CODE;
import static com.stevesoltys.backup.activity.MainActivity.OPEN_DOCUMENT_TREE_REQUEST_CODE;
import static com.stevesoltys.backup.settings.SettingsManager.getBackupFolderUri;
import static com.stevesoltys.backup.settings.SettingsManager.getBackupPassword;
import static com.stevesoltys.backup.settings.SettingsManager.setBackupFolderUri;
import static com.stevesoltys.backup.settings.SettingsManager.setBackupsScheduled;
import static java.util.Objects.requireNonNull;
import static java.util.concurrent.TimeUnit.DAYS;

/**
 * @author Steve Soltys
 * @author Torsten Grote
 */
public class MainActivityController {

    private static final String TAG = MainActivityController.class.getName();

    private static final String DOCUMENT_MIME_TYPE = "application/octet-stream";
    private static final String DOCUMENT_SUFFIX = "yyyy-MM-dd_HH_mm_ss";

    void onBackupButtonClicked(Activity parent) {
        Uri folderUri = getBackupFolderUri(parent);
        if (folderUri == null) {
            showChooseFolderActivity(parent, true);
        } else {
            try {
                // ensure that backup service is started
                parent.startService(new Intent(parent, ConfigurableBackupTransportService.class));

                Uri fileUri = createBackupFile(parent.getContentResolver(), folderUri);
                showCreateBackupActivity(parent, fileUri);

            } catch (IOException e) {
                Log.w(TAG, "Error creating backup file: ", e);
                showChooseFolderActivity(parent, true);
            }
        }
    }

    boolean isChangeBackupLocationButtonVisible(Activity parent) {
        return getBackupFolderUri(parent) != null;
    }

    private void showChooseFolderActivity(Activity parent, boolean continueToBackup) {
        Intent openTreeIntent = new Intent(ACTION_OPEN_DOCUMENT_TREE);
        openTreeIntent.addFlags(FLAG_GRANT_PERSISTABLE_URI_PERMISSION |
                FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION);

        try {
            Intent documentChooser = Intent.createChooser(openTreeIntent, "Select the backup location");
            int requestCode = continueToBackup ? OPEN_DOCUMENT_TREE_BACKUP_REQUEST_CODE : OPEN_DOCUMENT_TREE_REQUEST_CODE;
            parent.startActivityForResult(documentChooser, requestCode);

        } catch (ActivityNotFoundException ex) {
            Toast.makeText(parent, "Please install a file manager.", Toast.LENGTH_SHORT).show();
        }
    }

    void showLoadDocumentActivity(Activity parent) {
        Intent loadDocumentIntent = new Intent(ACTION_OPEN_DOCUMENT);
        loadDocumentIntent.addCategory(CATEGORY_OPENABLE);
        loadDocumentIntent.setType(DOCUMENT_MIME_TYPE);

        try {
            Intent documentChooser = Intent.createChooser(loadDocumentIntent, "Select the backup location");
            parent.startActivityForResult(documentChooser, MainActivity.LOAD_DOCUMENT_REQUEST_CODE);

        } catch (ActivityNotFoundException ex) {
            Toast.makeText(parent, "Please install a file manager.", Toast.LENGTH_SHORT).show();
        }
    }

    boolean onAutomaticBackupsButtonClicked(Activity parent) {
        if (getBackupFolderUri(parent) == null || getBackupPassword(parent) == null) {
            Toast.makeText(parent, "Please make at least one manual backup first.", Toast.LENGTH_SHORT).show();
            return false;
        }
        final ComponentName serviceName = new ComponentName(parent, BackupJobService.class);
        JobInfo job = new JobInfo.Builder(JOB_ID_BACKGROUND_BACKUP, serviceName)
                .setRequiredNetworkType(NETWORK_TYPE_UNMETERED)
                .setRequiresBatteryNotLow(true)
                .setRequiresStorageNotLow(true)  // TODO warn the user instead
                .setPeriodic(DAYS.toMillis(1))
                .setRequiresCharging(true)
                .setPersisted(true)
                .build();
        JobScheduler scheduler = requireNonNull(parent.getSystemService(JobScheduler.class));
        scheduler.schedule(job);
        setBackupsScheduled(parent);
        Toast.makeText(parent, "Backups will run automatically now", Toast.LENGTH_SHORT).show();
        return true;
    }

    void onChangeBackupLocationButtonClicked(Activity parent) {
        showChooseFolderActivity(parent, false);
    }

    void handleChooseFolderResult(Intent result, Activity parent, boolean continueToBackup) {

        if (result == null || result.getData() == null) {
            return;
        }

        Uri folderUri = result.getData();
        ContentResolver contentResolver = parent.getContentResolver();

        // persist permission to access backup folder across reboots
        int takeFlags = result.getFlags() &
                (FLAG_GRANT_READ_URI_PERMISSION | FLAG_GRANT_WRITE_URI_PERMISSION);
        contentResolver.takePersistableUriPermission(folderUri, takeFlags);

        // store backup folder location in settings
        setBackupFolderUri(parent, folderUri);

        if (!continueToBackup) return;

        try {
            // create a new backup file in folder
            Uri fileUri = createBackupFile(contentResolver, folderUri);

            showCreateBackupActivity(parent, fileUri);

        } catch (IOException e) {
            Log.e(TAG, "Error creating backup file: ", e);
            // TODO show better error message once more infrastructure is in place
            Toast.makeText(parent, "Error creating backup file", Toast.LENGTH_SHORT).show();
        }
    }

    private void showCreateBackupActivity(Activity parent, Uri fileUri) {
        Intent intent = new Intent(parent, CreateBackupActivity.class);
        intent.setData(fileUri);
        parent.startActivity(intent);
    }

    void handleLoadDocumentResult(Intent result, Activity parent) {

        if (result == null) {
            return;
        }

        Intent intent = new Intent(parent, RestoreBackupActivity.class);
        intent.setData(result.getData());
        parent.startActivity(intent);
    }

    public static Uri createBackupFile(ContentResolver contentResolver, Uri folderUri) throws IOException {
        Uri documentUri = buildDocumentUriUsingTree(folderUri, getTreeDocumentId(folderUri));
        try {
            Uri fileUri = createDocument(contentResolver, documentUri, DOCUMENT_MIME_TYPE, getBackupFileName());
            if (fileUri == null) throw new IOException();
            return fileUri;

        } catch (SecurityException e) {
            // happens when folder was deleted and thus Uri permission don't exist anymore
            throw new IOException(e);
        }
    }

    private static String getBackupFileName() {
        SimpleDateFormat dateFormat = new SimpleDateFormat(DOCUMENT_SUFFIX, Locale.US);
        String date = dateFormat.format(new Date());
        return "backup-" + date;
    }

}