package com.topjohnwu.magisk.view;

import android.app.Activity;
import android.content.Context;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.ProgressBar;
import android.widget.TextView;

import com.topjohnwu.magisk.App;
import com.topjohnwu.magisk.Const;
import com.topjohnwu.magisk.R;
import com.topjohnwu.magisk.utils.ISafetyNetHelper;
import com.topjohnwu.magisk.view.dialogs.CustomAlertDialog;
import com.topjohnwu.net.Networking;
import com.topjohnwu.superuser.Shell;

import java.io.File;

import androidx.annotation.StringRes;
import androidx.cardview.widget.CardView;
import butterknife.BindColor;
import butterknife.BindView;
import butterknife.OnClick;
import butterknife.Unbinder;
import dalvik.system.DexClassLoader;

public class SafetyNet implements ISafetyNetHelper.Callback {

    public static final File EXT_APK =
            new File(App.self.getFilesDir().getParent() + "/snet", "snet.apk");

    /*@BindView(R.id.safetyNet_card) */ CardView safetyNetCard;
    @BindView(R.id.safetyNet_refresh) ImageView safetyNetRefreshIcon;
    @BindView(R.id.safetyNet_status) TextView safetyNetStatusText;
    @BindView(R.id.safetyNet_check_progress) ProgressBar safetyNetProgress;
    @BindView(R.id.safetyNet_expand) ViewGroup expandLayout;
    @BindView(R.id.cts_status_icon) ImageView ctsStatusIcon;
    @BindView(R.id.cts_status) TextView ctsStatusText;
    @BindView(R.id.basic_status_icon) ImageView basicStatusIcon;
    @BindView(R.id.basic_status) TextView basicStatusText;

    @BindColor(R.color.red500) int colorBad;
    @BindColor(R.color.green500) int colorOK;

    public Unbinder unbinder;
    private final ExpandableViewHolder expandable;

    public SafetyNet(View v) {
        unbinder = new SafetyNet_ViewBinding(this, v);
        expandable = new ExpandableViewHolder(expandLayout);
        Context context = v.getContext();
        safetyNetCard.setVisibility(hasGms(context) && Networking.checkNetworkStatus(context) ?
                View.VISIBLE : View.GONE);
    }

    public static void dyRun(Activity activity, Object callback) throws Exception {
        DexClassLoader loader = new DexClassLoader(EXT_APK.getPath(), EXT_APK.getParent(),
                null, ISafetyNetHelper.class.getClassLoader());
        Class<?> clazz = loader.loadClass("com.topjohnwu.snet.Snet");
        ISafetyNetHelper helper = (ISafetyNetHelper) clazz.getMethod("newHelper",
                Class.class, String.class, Activity.class, Object.class)
                .invoke(null, ISafetyNetHelper.class, EXT_APK.getPath(), activity, callback);
        if (helper.getVersion() < Const.SNET_EXT_VER)
            throw new Exception();
        helper.attest();
    }

    public void reset() {
        safetyNetStatusText.setText(R.string.safetyNet_check_text);
        expandable.setExpanded(false);
    }

    @Override
    public void onResponse(int response) {
        safetyNetProgress.setVisibility(View.GONE);
        safetyNetRefreshIcon.setVisibility(View.VISIBLE);
        if ((response & 0x0F) == 0) {
            safetyNetStatusText.setText(R.string.safetyNet_check_success);

            boolean b;
            b = (response & ISafetyNetHelper.CTS_PASS) != 0;
            ctsStatusText.setText("ctsProfile: " + b);
            ctsStatusIcon.setImageResource(b ? R.drawable.ic_check_circle : R.drawable.ic_cancel);
            ctsStatusIcon.setColorFilter(b ? colorOK : colorBad);

            b = (response & ISafetyNetHelper.BASIC_PASS) != 0;
            basicStatusText.setText("basicIntegrity: " + b);
            basicStatusIcon.setImageResource(b ? R.drawable.ic_check_circle : R.drawable.ic_cancel);
            basicStatusIcon.setColorFilter(b ? colorOK : colorBad);

            expandable.expand();
        } else {
            @StringRes int resid;
            switch (response) {
                case ISafetyNetHelper.RESPONSE_ERR:
                    resid = R.string.safetyNet_res_invalid;
                    break;
                case ISafetyNetHelper.CONNECTION_FAIL:
                default:
                    resid = R.string.safetyNet_api_error;
                    break;
            }
            safetyNetStatusText.setText(resid);
        }
    }

    @OnClick(R.id.safetyNet_refresh)
    void safetyNet(View v) {
        Runnable task = () -> {
            safetyNetProgress.setVisibility(View.VISIBLE);
            safetyNetRefreshIcon.setVisibility(View.INVISIBLE);
            safetyNetStatusText.setText(R.string.checking_safetyNet_status);
            check((Activity) v.getContext());
            expandable.collapse();
        };
        if (!EXT_APK.exists()) {
            // Show dialog
            new CustomAlertDialog(v.getContext())
                    .setTitle(R.string.proprietary_title)
                    .setMessage(R.string.proprietary_notice)
                    .setCancelable(true)
                    .setPositiveButton(R.string.yes, (d, i) -> task.run())
                    .setNegativeButton(R.string.no_thanks, null)
                    .show();
        } else {
            task.run();
        }
    }

    private void check(Activity activity) {
        try {
            dyRun(activity, this);
        } catch (Exception ignored) {
            Shell.sh("rm -rf " + EXT_APK.getParent()).exec();
            EXT_APK.getParentFile().mkdir();
            Networking.get(Const.Url.SNET_URL).getAsFile(EXT_APK, f -> {
                try {
                    dyRun(activity, this);
                } catch (Exception e) {
                    e.printStackTrace();
                    onResponse(-1);
                }
            });
        }
    }

    private boolean hasGms(Context context) {
        PackageManager pm = context.getPackageManager();
        PackageInfo info;
        try {
            info = pm.getPackageInfo("com.google.android.gms", 0);
        } catch (PackageManager.NameNotFoundException e) {
            return false;
        }
        return info.applicationInfo.enabled;
    }
}
