/* Copyright 2014-2023 askanimus@gmail.com */

/* This File is part of "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2).
 *
 * "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2) is free software: you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation, either version 3 of the License, or
 * (at your option) any later version.
 *
 * "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2) is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2).  If not, see <http://www.gnu.org/licenses/>.
 *
 * Diese Datei ist Teil von "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2).
 *
 * "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2) ist Freie Software: Sie können es unter den Bedingungen
 * der GNU General Public License, wie von der Free Software Foundation,
 * Version 3 der Lizenz oder (nach Ihrer Wahl) jeder neueren
 * veröffentlichten Version, weiter verteilen und/oder modifizieren.
 *
 * "Arbeitszeitkonto" (askanimus.arbeitszeiterfassung2) wird in der Hoffnung, dass es nützlich sein wird, aber
 * OHNE JEDE GEWÄHRLEISTUNG, bereitgestellt; sogar ohne die implizite
 * Gewährleistung der MARKTFÄHIGKEIT oder EIGNUNG FÜR EINEN BESTIMMTEN ZWECK.
 * Siehe die GNU General Public License für weitere Details.
 *
 * Sie sollten eine Kopie der GNU General Public License zusammen mit diesem
 * Programm erhalten haben. Wenn nicht, siehe <https://www.gnu.org/licenses/>.
 */
package askanimus.arbeitszeiterfassung2.datensicherung;

import static androidx.core.app.NotificationCompat.EXTRA_NOTIFICATION_ID;

import android.Manifest;
import android.app.PendingIntent;
import android.content.BroadcastReceiver;
import android.content.ContentValues;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.database.sqlite.SQLiteDatabase;
import android.os.Build;
import android.os.Environment;

import androidx.core.app.ActivityCompat;
import androidx.core.app.NotificationCompat;
import androidx.core.app.NotificationManagerCompat;
import androidx.documentfile.provider.DocumentFile;

import java.io.File;
import java.io.IOException;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.Collections;
import java.util.Comparator;
import java.util.Date;
import java.util.Locale;
import java.util.Objects;

import askanimus.arbeitszeiterfassung2.R;
import askanimus.arbeitszeiterfassung2.StorageHelper;
import askanimus.arbeitszeiterfassung2.datenbank.DatenbankHelper;
import askanimus.arbeitszeiterfassung2.setup.ASettings;
import askanimus.arbeitszeiterfassung2.setup.ISettings;

public class AutoBackup_Receiver extends BroadcastReceiver implements ISettings {
    private StorageHelper mStorageHelper;
    private Context mContext;

    @Override
    public void onReceive(Context context, Intent intent) {
        mContext = context;
        ASettings.init(context, this::recive);
    }

    private void recive() {
        /*int backupIntertvall = ASettings.mPreferenzen.getInt(KEY_AUTOBACKUP_INTERVAL, AUTOBACKUP_NO);
        if (backupIntertvall > AUTOBACKUP_NO) {
            // backupIntertvall = AUTOBACKUP_INTERVAL[backupIntertvall];
            // Datum der aKtuellen Sicherung speichern
            SharedPreferences.Editor mEditor = ASettings.mPreferenzen.edit();
            Calendar next = Calendar.getInstance();
            next.setTimeInMillis(new Date().getTime());//ASettings.mPreferenzen.getLong(KEY_AUTOBACKUP_NAECHSTES, new Date().getTime()));
            next.set(Calendar.SECOND, 0);
            mEditor.putLong(KEY_AUTOBACKUP_LETZTES, next.getTimeInMillis());
            next.add(
                    backupIntertvall,
                    ASettings.mPreferenzen.getInt(KEY_AUTOBACKUP_SCHRITTE, 1)
            );
            mEditor.putLong(KEY_AUTOBACKUP_OFFSET, next.getTimeInMillis());
            mEditor.apply();
        }*/
        String mExportPfad = Environment.getExternalStorageDirectory().getAbsolutePath()
                + File.separator
                + ASettings.res.getString(R.string.app_verzeichnis);
        mExportPfad = ASettings.mPreferenzen.getString(ISettings.KEY_BACKUP_DIR, mExportPfad);

        if (mExportPfad != null) {
            mStorageHelper = new StorageHelper(
                    mContext,
                    mExportPfad,
                    DatenbankHelper.DB_F_BACKUP_DIR,
                    ISettings.KEY_BACKUP_DIR,
                    true,
                    ISettings.REQ_FOLDER_PICKER_WRITE_BACKUP/*,
                        this::sicherungDB*/
            );
            sicherungDB(false);
        }
    }

    /*
     * Sicherung anlegen, Erfolgsmeldung als Notification ausgeben
     */
    private void sicherungDB(boolean toast) {
        new Thread(() -> {
            int mStatus = AAutoBackup.STATUS_OK;
            /*int appVersionCode;
            try {
                appVersionCode = mContext
                        .getPackageManager()
                        .getPackageInfo(mContext.getPackageName(), 0)
                        .versionCode;
            } catch (PackageManager.NameNotFoundException e) {
                throw new RuntimeException(e);
            }*/
            // Datensicherung anlegen
            if (mStorageHelper.isWritheable()) {
                // SQLiteDatabase mDatenbank = ASettings.stundenDBHelper.getWritableDatabase();
                // die allgem. Einstellungen sichern
                ContentValues mWerte = new ContentValues();
                mWerte.put(
                        DatenbankHelper.DB_F_VERSION,
                        ASettings.mPreferenzen.getLong(ISettings.KEY_VERSION_APP, 0)
                        );
                mWerte.put(DatenbankHelper.DB_F_JOB, ASettings.aktJob.getId());
                mWerte.put(DatenbankHelper.DB_F_VIEW, ASettings.mPreferenzen.getInt(ISettings.KEY_ANZEIGE_VIEW, ISettings.VIEW_TAG));

                ASettings.mDatenbank.update(DatenbankHelper.DB_T_SETTINGS, mWerte,
                        DatenbankHelper.DB_F_ID + "=?", new String[]{String.valueOf(1)});

                // die Datenbank in XML File exportieren
                Datenbank_Backup mBackup = new Datenbank_Backup(mContext, mStorageHelper);
                // ASettings.mDatenbank.close();
                //try {
                try {
                    mBackup.backup();
                    // Datum der aKtuellen erfolgreichen Sicherung speichern
                    SharedPreferences.Editor mEditor = ASettings.mPreferenzen.edit();
                    Calendar next = Calendar.getInstance();
                    next.setTimeInMillis(new Date().getTime());//ASettings.mPreferenzen.getLong(KEY_AUTOBACKUP_NAECHSTES, new Date().getTime()));
                    next.set(Calendar.SECOND, 0);
                    mEditor.putLong(KEY_AUTOBACKUP_LETZTES, next.getTimeInMillis()).apply();
                } catch (IOException ioe) {
                    mStatus = AAutoBackup.STATUS_FAIL;
                }
                /*} catch (NullPointerException | ParserConfigurationException | IOException |
                         TransformerException e) {
                    if (!mStorageHelper.isExists()) {
                        mStatus = STATUS_NO_DIRECTORY;
                    } else if (!mStorageHelper.isWritheable()) {
                        mStatus = STATUS_NO_ACCESS;
                    } else {
                        mStatus = STATUS_FAIL;
                    }
                } catch (OutOfMemoryError me) {
                    mStatus = STATUS_NO_MEMORY;
                }*/
                // älteste Sicherung löschen
                loescheAlteSicherungen();
            }

            // Erfolgsmeldung
            showNotification(mContext, mStatus);
        }).start();
    }

    /*
     * älteste Sicherungen laut Einstellungen löschen
     */
    private void loescheAlteSicherungen() {
        ArrayList<DocumentFile> fSicherungen = new ArrayList<>();

        // Dateien einlesen
        int anzahl = ASettings.mPreferenzen.getInt(KEY_AUTOBACKUP_ANZAHL, 0);
        DocumentFile dir = mStorageHelper.getVerzeichnisFile();
        if (anzahl > 0 && dir != null && dir.exists()) {
            //Calendar cal = Calendar.getInstance();
            //cal.setTimeInMillis(ASettings.mPreferenzen.getLong(KEY_AUTOBACKUP_LETZTES, new Date().getTime()));
            //cal.add(backupIntertvall, -(anzahl * ASettings.mPreferenzen.getInt(KEY_AUTOBACKUP_SCHRITTE, 1)));
            //long letzte = cal.getTimeInMillis();

            // Liste einlesen
            // doppelte Sicherungen (enthalten im Namen '(x)') löschen
            for (DocumentFile docFile : dir.listFiles()) {
                if (docFile.getName() != null)
                    if (
                            docFile.isFile() &&
                            (docFile.getName().endsWith(".xml") || docFile.getName().endsWith(".db"))
                    ) {
                        if (docFile.getName().contains("(")) {
                            docFile.delete();
                        } else {
                            fSicherungen.add(docFile);
                        }
                    }
            }

            // Die Liste aufsteigend nach Dateiname (Datum und Uhrzeit) sortieren
            Collections.sort(fSicherungen, new Comparator<DocumentFile>() {
                final DateFormat f = new SimpleDateFormat(
                        "dd-MM-yyyy_hh.mm.ss",
                        Locale.getDefault());

                @Override
                public int compare(DocumentFile f1, DocumentFile f2) {
                    String o1 = f1.getName();
                    String o2 = f2.getName();
                    if (o1 != null & o2 != null) {
                        o1 = o1.replace(".xml", "");
                        o1 = o1.replace(ASettings.res.getString(R.string.sich_vom_datei), "");
                        o2 = o2.replace(".xml", "");
                        o2 = o2.replace(ASettings.res.getString(R.string.sich_vom_datei), "");

                        try {
                            return Objects.requireNonNull(
                                    f.parse(o2)).compareTo(f.parse(o1)
                            );
                        } catch (ParseException e) {
                            return 0;
                        }
                    }
                    return 0;
                }
            });

            // alle bis auf die letzten x Einträge ( die ersten in der Liste löschen
            for (DocumentFile file : fSicherungen) {
                if (anzahl <= 0) {
                    file.delete();
                } else {
                    anzahl--;
                }
            }
        }
    }

    private void showNotification(Context context, int status) {
        /*
        // Notification Chanel
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
            CharSequence name = context.getResources().getString(R.string.autobackup);
            String description = context.getResources().getString(R.string.descript_autobackup);
            int importance = NotificationManager.IMPORTANCE_LOW;
            NotificationChannel channel = new NotificationChannel(CHANNEL_ID, name, importance);
            channel.setDescription(description);
            // Register the channel with the system; you can't change the importance
            // or other notification behaviors after this
            NotificationManager notificationManager = context.getSystemService(NotificationManager.class);
            notificationManager.createNotificationChannel(channel);
        }*/

        // die Meldung zusammenbauen
        String meldung;
        String titel;

        switch (status) {
            case AAutoBackup.STATUS_OK:
                titel = context.getResources().getString(R.string.not_titel_autobackup);
                meldung = context.getResources().getString(R.string.not_text_autobackup);
                break;
            case AAutoBackup.STATUS_NO_DIRECTORY:
                titel = context.getResources().getString(R.string.not_titel_autobackup_fail);
                meldung = context.getResources().getString(
                        R.string.not_text_autobackup_fail,
                        context.getResources().getString(R.string.not_no_exists,
                                mStorageHelper.getPfadSubtree())
                );
                break;
            case AAutoBackup.STATUS_NO_ACCESS:
                titel = context.getResources().getString(R.string.not_titel_autobackup_fail);
                meldung = context.getResources().getString(
                        R.string.not_text_autobackup_fail,
                        context.getResources().getString(R.string.not_no_writeable,
                        mStorageHelper.getPfadSubtree())
                );
                break;
            case AAutoBackup.STATUS_NO_MEMORY:
                titel = context.getResources().getString(R.string.not_titel_autobackup_fail);
                meldung = context.getResources().getString(
                        R.string.not_text_autobackup_fail,
                        context.getResources().getString(R.string.not_no_memory)
                );
                break;
            default:
                titel = context.getResources().getString(R.string.not_titel_autobackup_fail);
                meldung = "";
        }

        NotificationManagerCompat notificationManager = NotificationManagerCompat.from(context);

        if (notificationManager.areNotificationsEnabled()) {
            if (ActivityCompat.checkSelfPermission(mContext, Manifest.permission.POST_NOTIFICATIONS) == PackageManager.PERMISSION_GRANTED) {
                NotificationCompat.Builder builder = new NotificationCompat.Builder(context, AAutoBackup.CHANNEL_ID)
                        .setSmallIcon(R.drawable.ic_stat_backup)
                        .setContentTitle(titel)
                        .setContentText(meldung)
                        .setStyle(new NotificationCompat.BigTextStyle()
                                .bigText(meldung))
                        .setPriority(NotificationCompat.PRIORITY_LOW);

                if (status == AAutoBackup.STATUS_NO_DIRECTORY || status == AAutoBackup.STATUS_NO_ACCESS) {
                    Intent intent = new Intent(mContext, Datensicherung_Activity.class);
                    //intent.setAction(Datensicherung_Activity.ACTIVITY_START);

                    PendingIntent pendingIntent = PendingIntent.getActivity(
                            mContext,
                            0,
                            intent,
                            (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) ? PendingIntent.FLAG_MUTABLE : 0);
                    intent.putExtra(EXTRA_NOTIFICATION_ID, 0);
                    builder.setContentIntent(pendingIntent);
                    builder.addAction(
                            R.drawable.ic_stat_backup,
                            context.getResources().getString(R.string.not_button),
                            pendingIntent
                    ).setAutoCancel(true);
                } else {
                    Intent intent = new Intent(mContext, Datensicherung_Activity.class);
                    //intent.setAction(Datensicherung_Activity.ACTIVITY_START);

                    PendingIntent pendingIntent = PendingIntent.getActivity(
                            mContext,
                            0,
                            intent,
                            (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) ? PendingIntent.FLAG_MUTABLE : 0
                    );
                    intent.putExtra(EXTRA_NOTIFICATION_ID, 0);
                    builder.setContentIntent(pendingIntent)
                            .setAutoCancel(true);
                }

                notificationManager.notify(666, builder.build());
            }
        }
    }


}
