package com.example.modifier;

import android.accessibilityservice.AccessibilityServiceInfo;
import android.accounts.AccountManager;
import android.accounts.AuthenticatorDescription;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.content.pm.PackageManager;
import android.content.pm.ServiceInfo;
import android.content.res.AssetManager;
import android.content.res.Resources;
import android.content.res.XmlResourceParser;
import android.os.Bundle;
import android.provider.Settings;
import android.text.TextUtils;
import android.util.Log;
import android.view.accessibility.AccessibilityManager;

import com.example.modifier.service.ModifierService;
import com.google.android.material.button.MaterialButton;
import com.google.android.material.progressindicator.CircularProgressIndicatorSpec;
import com.google.android.material.progressindicator.IndeterminateDrawable;

import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.RandomStringUtils;
import org.apache.commons.lang3.StringUtils;
import org.xmlpull.v1.XmlPullParser;

import java.io.DataOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.lang.reflect.Method;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Objects;

public class Utils {
    private static final String TAG = "Modifier";

    public static Context getContext() {
        try {
            Class<?> activityThreadClass = Class.forName("android.app.ActivityThread");
            Method currentActivityThreadMethod = activityThreadClass.getMethod("currentActivityThread");
            currentActivityThreadMethod.setAccessible(true);
            Object currentActivityThread = currentActivityThreadMethod.invoke(null);
            Method getApplicationMethod = activityThreadClass.getMethod("getApplication");
            getApplicationMethod.setAccessible(true);
            return (Context) getApplicationMethod.invoke(currentActivityThread);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    public static String runAsRoot(String... cmds) throws IOException, InterruptedException {
        Log.i(TAG, "Trying to run as root");
        Process p = new ProcessBuilder("su", "-M").start();

        StringBuilder res = new StringBuilder();
        StringBuilder err = new StringBuilder();
        new Thread(() -> {
            try {
                res.append(IOUtils.toString(p.getInputStream(), StandardCharsets.UTF_8));
            } catch (IOException ignored) {
            }
        }).start();

        new Thread(() -> {
            try {
                err.append(IOUtils.toString(p.getErrorStream(), StandardCharsets.UTF_8));
            } catch (IOException ignored) {
            }
        }).start();

        DataOutputStream outputStream = new DataOutputStream(p.getOutputStream());
        for (String cmd : cmds) {
            outputStream.writeBytes(cmd + "\n");
            outputStream.flush();
            Log.i(TAG, "Running command: " + cmd);
        }
        Thread.sleep(500);
        outputStream.writeBytes("exit\n");
        outputStream.flush();
        p.waitFor();

        Log.i(TAG, "Output: " + res);
        if (err.length() > 0) {
            Log.i(TAG, "Error: " + err);
        }

        return res.toString();
    }

    public static String getUniqueID() {
        Context context = getContext();
        Objects.requireNonNull(context);
        SharedPreferences sharedPrefs = context.getSharedPreferences(BuildConfig.APPLICATION_ID, Context.MODE_PRIVATE);
        String uniqueID = sharedPrefs.getString("unique_id", null);
        if (StringUtils.isBlank(uniqueID)) {
            try {
                uniqueID = Settings.Secure.getString(context.getContentResolver(), Settings.Secure.ANDROID_ID);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        if (StringUtils.isBlank(uniqueID)) {
            uniqueID = java.util.UUID.randomUUID().toString();
        }
        sharedPrefs.edit().putString("unique_id", uniqueID).apply();
        return uniqueID;
    }

    public static String generateIMEI() {
        int pos;
        int[] str = Arrays.stream(("35684610" + RandomStringUtils.randomNumeric(7)).split("")).mapToInt(Integer::parseInt).toArray();
        int sum = 0;
        int final_digit;
        int t;
        int len_offset;
        int len = 15;
        String imei = "";

        len_offset = (len + 1) % 2;
        for (pos = 0; pos < len - 1; pos++) {
            if ((pos + len_offset) % 2 != 0) {
                t = str[pos] * 2;
                if (t > 9) {
                    t -= 9;
                }
                sum += t;
            } else {
                sum += str[pos];
            }
        }

        final_digit = (10 - (sum % 10)) % 10;
        str[len - 1] = final_digit;

        for (int d : str) {
            imei += String.valueOf(d);
        }

        return imei;
    }

    public static String generateIMEI1() {
        int pos;
        int[] str = new int[]{0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0};
        int sum = 0;
        int final_digit;
        int t;
        int len_offset;
        int len = 15;
        String imei = "";

        String[] rbi = new String[]{"01", "10", "30", "33", "35", "44", "45", "49", "50", "51", "52", "53", "54", "86", "91", "98", "99"};
        String[] arr = rbi[(int) Math.floor(Math.random() * rbi.length)].split("");
        str[0] = Integer.parseInt(arr[0]);
        str[1] = Integer.parseInt(arr[1]);
        pos = 2;

        while (pos < len - 1) {
            str[pos++] = (int) (Math.floor(Math.random() * 10) % 10);
        }

        len_offset = (len + 1) % 2;
        for (pos = 0; pos < len - 1; pos++) {
            if ((pos + len_offset) % 2 != 0) {
                t = str[pos] * 2;
                if (t > 9) {
                    t -= 9;
                }
                sum += t;
            } else {
                sum += str[pos];
            }
        }

        final_digit = (10 - (sum % 10)) % 10;
        str[len - 1] = final_digit;

        for (int d : str) {
            imei += String.valueOf(d);
        }

        return imei;
    }

    public static void makeLoadingButton(Context context, MaterialButton button) {
        CircularProgressIndicatorSpec spec = new CircularProgressIndicatorSpec(context, null, 0,
                com.google.android.material.R.style.Widget_Material3_CircularProgressIndicator_ExtraSmall);
        IndeterminateDrawable progressIndicatorDrawable = IndeterminateDrawable.createCircularDrawable(context, spec);
        button.setIcon(progressIndicatorDrawable);
        button.setEnabled(false);
    }

    public static boolean copyAssetFolder(AssetManager assetManager,
                                          String fromAssetPath, String toPath) {
        try {
            String[] files = assetManager.list(fromAssetPath);
            new File(toPath).mkdirs();
            boolean res = true;
            for (String file : files)
                if (file.contains("."))
                    res &= copyAsset(assetManager,
                            fromAssetPath + "/" + file,
                            toPath + "/" + file);
                else
                    res &= copyAssetFolder(assetManager,
                            fromAssetPath + "/" + file,
                            toPath + "/" + file);
            return res;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public static boolean copyAsset(AssetManager assetManager,
                                    String fromAssetPath, String toPath) {
        if (new File(toPath).exists())
            return true;
        InputStream in = null;
        OutputStream out = null;
        try {
            in = assetManager.open(fromAssetPath);
            new File(toPath).createNewFile();
            out = Files.newOutputStream(Paths.get(toPath));
            IOUtils.copy(in, out);
            in.close();
            out.flush();
            out.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
            return false;
        }
    }

    public static int dp2px(Context context, int dp) {
        float scale = context.getResources().getDisplayMetrics().density;
        return (int) (dp * scale + 0.5f);
    }

    public static void startPreferenceActivity(String type) {
        Context context = getContext();
        AccountManager accountManager = AccountManager.get(context);
        AuthenticatorDescription[] descriptions = accountManager.getAuthenticatorTypes();
        AuthenticatorDescription neededDescription = null;
        for (AuthenticatorDescription description : descriptions) {
            if (description.type.equals(type)) {
                neededDescription = description;
                break;
            }
        }
        if (neededDescription != null) {
            String packageName = neededDescription.packageName;
            int prefsId = neededDescription.accountPreferencesId;
            try {
                Resources resources = context.getPackageManager().getResourcesForApplication(packageName);
                XmlResourceParser xpp = resources.getLayout(prefsId);
                xpp.next();
                String action = null;
                String targetPackage = packageName; //default to the account pref package name...?
                String targetClass = null;
                int eventType = xpp.getEventType();
                while (eventType != XmlPullParser.END_DOCUMENT) {
                    if (eventType == XmlPullParser.START_TAG) {
                        if (xpp.getName().equals("intent")) {
                            int count = xpp.getAttributeCount();
                            for (int i = 0; i < count; i++) {
                                String name = xpp.getAttributeName(i);
                                if (name.equals("action")) {
                                    action = xpp.getAttributeValue(i);
                                } else if (name.equals("targetPackage")) {
                                    targetPackage = xpp.getAttributeValue(i);
                                } else if (name.equals("targetClass")) {
                                    targetClass = xpp.getAttributeValue(i);
                                }
                            }
                        }
                    }
                    eventType = xpp.next();
                }
                if (action != null) {
                    context.startActivity(new Intent(action));
                } else if (targetClass != null) {
                    context.startActivity(new Intent(context.createPackageContext(targetPackage, Context.CONTEXT_IGNORE_SECURITY), Class.forName(targetClass)));
                }
            } catch (PackageManager.NameNotFoundException e) {
                e.printStackTrace();
            } catch (Exception e) {
                e.printStackTrace();
            }

        }
    }
}
