package com.fox2code.mmm;

import android.view.View;
import android.widget.Toast;

import androidx.annotation.AttrRes;
import androidx.annotation.DrawableRes;
import androidx.annotation.StringRes;

import com.fox2code.foxcompat.app.FoxActivity;
import com.fox2code.mmm.installer.InstallerInitializer;
import com.fox2code.mmm.module.ModuleViewListBuilder;
import com.fox2code.mmm.repo.RepoManager;
import com.fox2code.mmm.utils.IntentHelper;
import com.fox2code.mmm.utils.io.Files;
import com.fox2code.mmm.utils.io.net.Http;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;

import timber.log.Timber;

interface NotificationTypeCst {
}

public enum NotificationType implements NotificationTypeCst {
    DEBUG(R.string.debug_build, R.drawable.ic_baseline_bug_report_24, com.google.android.material.R.attr.colorSecondary, com.google.android.material.R.attr.colorOnSecondary) {
        @Override
        public boolean shouldRemove() {
            return !BuildConfig.DEBUG;
        }
    },
    SHOWCASE_MODE(R.string.showcase_mode, R.drawable.ic_baseline_lock_24,
            androidx.appcompat.R.attr.colorPrimary, com.google.android.material.R.attr.colorOnPrimary) {
        @Override
        public boolean shouldRemove() {
            return !MainApplication.isShowcaseMode();
        }
    },
    NO_MAGISK(R.string.fail_magisk_missing, R.drawable.ic_baseline_numbers_24, v ->
            IntentHelper.openUrl(v.getContext(),
                    "https://github.com/topjohnwu/Magisk/blob/master/docs/install.md")) {
        @Override
        public boolean shouldRemove() {
            return InstallerInitializer.getErrorNotification() != this;
        }
    },
    NO_ROOT(R.string.fail_root_magisk, R.drawable.ic_baseline_numbers_24) {
        @Override
        public boolean shouldRemove() {
            return InstallerInitializer.getErrorNotification() != this;
        }
    },
    ROOT_DENIED(R.string.fail_root_denied, R.drawable.ic_baseline_numbers_24) {
        @Override
        public boolean shouldRemove() {
            return InstallerInitializer.getErrorNotification() != this;
        }
    },
    MAGISK_OUTDATED(R.string.magisk_outdated, R.drawable.ic_baseline_update_24, v -> IntentHelper.openUrl(v.getContext(), "https://github.com/topjohnwu/Magisk/releases")) {
        @Override
        public boolean shouldRemove() {
            return InstallerInitializer.peekMagiskPath() == null ||
                    InstallerInitializer.peekMagiskVersion() >=
                            Constants.MAGISK_VER_CODE_INSTALL_COMMAND;
        }
    },
    NO_INTERNET(R.string.fail_internet, R.drawable.ic_baseline_cloud_off_24) {
        @Override
        public boolean shouldRemove() {
            return RepoManager.getINSTANCE().hasConnectivity();
        }
    },
    REPO_UPDATE_FAILED(R.string.repo_update_failed, R.drawable.ic_baseline_cloud_off_24) {
        @Override
        public boolean shouldRemove() {
            return RepoManager.getINSTANCE().isLastUpdateSuccess();
        }
    },
    NEED_CAPTCHA_ANDROIDACY(R.string.androidacy_need_captcha, R.drawable.ic_baseline_refresh_24, v ->
            IntentHelper.openUrlAndroidacy(v.getContext(),
                    "https://" + Http.needCaptchaAndroidacyHost() + "/", false)) {
        @Override
        public boolean shouldRemove() {
            return !RepoManager.isAndroidacyRepoEnabled()
                    || !Http.needCaptchaAndroidacy();
        }
    },
    NO_WEB_VIEW(R.string.no_web_view, R.drawable.ic_baseline_android_24) {
        @Override
        public boolean shouldRemove() {
            return Http.hasWebView();
        }
    },
    UPDATE_AVAILABLE(R.string.app_update_available, R.drawable.ic_baseline_system_update_24,
            androidx.appcompat.R.attr.colorPrimary, com.google.android.material.R.attr.colorOnPrimary, v -> IntentHelper.openUrl(v.getContext(),
                    "https://github.com/Fox2Code/FoxMagiskModuleManager/releases"), false) {
        @Override
        public boolean shouldRemove() {
            return !AppUpdateManager.getAppUpdateManager().peekShouldUpdate();
        }
    },
    INSTALL_FROM_STORAGE(R.string.install_from_storage, R.drawable.ic_baseline_storage_24,
            androidx.appcompat.R.attr.colorBackgroundFloating, com.google.android.material.R.attr.colorOnBackground, v -> {
        FoxActivity compatActivity = FoxActivity.getFoxActivity(v);
        final File module = new File(compatActivity.getCacheDir(),
                "installer" + File.separator + "module.zip");
        IntentHelper.openFileTo(compatActivity, module, (d, u, s) -> {
            if (s == IntentHelper.RESPONSE_FILE) {
                try {
                    if (needPatch(d)) {
                        Files.patchModuleSimple(Files.read(d),
                                new FileOutputStream(d));
                    }
                    if (needPatch(d)) {
                        if (d.exists() && !d.delete())
                            Timber.w("Failed to delete non module zip");
                        Toast.makeText(compatActivity,
                                R.string.invalid_format, Toast.LENGTH_SHORT).show();
                    } else {
                        IntentHelper.openInstaller(compatActivity, d.getAbsolutePath(),
                                compatActivity.getString(
                                        R.string.local_install_title), null, null, false,
                                BuildConfig.DEBUG && // Use debug mode if no root
                                        InstallerInitializer.peekMagiskPath() == null);
                    }
                } catch (IOException ignored) {
                    if (d.exists() && !d.delete())
                        Timber.w("Failed to delete invalid module");
                    Toast.makeText(compatActivity,
                            R.string.invalid_format, Toast.LENGTH_SHORT).show();
                }
            } else if (s == IntentHelper.RESPONSE_URL) {
                IntentHelper.openInstaller(compatActivity, u.toString(),
                        compatActivity.getString(
                                R.string.remote_install_title), null, null, false,
                        BuildConfig.DEBUG && // Use debug mode if no root
                                InstallerInitializer.peekMagiskPath() == null);
            }
        });
    }, false) {
        @Override
        public boolean shouldRemove() {
            return !BuildConfig.DEBUG &&
                    (MainApplication.isShowcaseMode() ||
                            InstallerInitializer.peekMagiskPath() == null);
        }
    };

    public static boolean needPatch(File target) {
        try (ZipFile zipFile = new ZipFile(target)) {
            boolean validEntries = zipFile.getEntry("module.prop") != null;
            // ensure there's no anykernel.sh
            validEntries &= zipFile.getEntry("anykernel.sh") == null;
            if (validEntries) {
                // Ensure id of module is not empty and matches ^[a-zA-Z][a-zA-Z0-9._-]+$ regex
                // We need to get the module.prop and parse the id= line
                ZipEntry moduleProp = zipFile.getEntry("module.prop");
                // Parse the module.prop
                if (moduleProp != null) {
                    // Find the line with id=, and check if it matches the regex
                    try (BufferedReader reader = new BufferedReader(new InputStreamReader(zipFile.getInputStream(moduleProp)))) {
                        String line;
                        while ((line = reader.readLine()) != null) {
                            if (line.startsWith("id=")) {
                                String id = line.substring(3);
                                return id.isEmpty() || !id.matches("^[a-zA-Z][a-zA-Z0-9._-]+$");
                            }
                        }
                    }
                } else {
                    return true;
                }
            } else {
                return true;
            }
        } catch (IOException e) {
            return true;
        }
        return false;
    }

    @StringRes
    public final int textId;
    @DrawableRes
    public final int iconId;
    @AttrRes
    public final int backgroundAttr;
    @AttrRes
    public final int foregroundAttr;
    public final View.OnClickListener onClickListener;
    public final boolean special;

    NotificationType(@StringRes int textId, int iconId) {
        this(textId, iconId, androidx.appcompat.R.attr.colorError, com.google.android.material.R.attr.colorOnPrimary);
    }

    NotificationType(@StringRes int textId, int iconId, View.OnClickListener onClickListener) {
        this(textId, iconId, androidx.appcompat.R.attr.colorError, com.google.android.material.R.attr.colorOnPrimary, onClickListener);
    }

    NotificationType(@StringRes int textId, int iconId, int backgroundAttr, int foregroundAttr) {
        this(textId, iconId, backgroundAttr, foregroundAttr, null);
    }

    NotificationType(@StringRes int textId, int iconId, int backgroundAttr, int foregroundAttr,
                     View.OnClickListener onClickListener) {
        this(textId, iconId, backgroundAttr, foregroundAttr, onClickListener, false);
    }

    NotificationType(@StringRes int textId, int iconId, int backgroundAttr, int foregroundAttr,
                     View.OnClickListener onClickListener, @SuppressWarnings("SameParameterValue") boolean special) {
        this.textId = textId;
        this.iconId = iconId;
        this.backgroundAttr = backgroundAttr;
        this.foregroundAttr = foregroundAttr;
        this.onClickListener = onClickListener;
        this.special = special;
    }

    public boolean shouldRemove() {
        // By default, remove the notification`
        return false;
    }

    public final void autoAdd(ModuleViewListBuilder moduleViewListBuilder) {
        if (!shouldRemove()) moduleViewListBuilder.addNotification(this);
    }
}
