package com.example.testsuite;

import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageManager;
import android.content.pm.ResolveInfo;
import android.util.Log;

import androidx.test.uiautomator.By;
import androidx.test.uiautomator.UiDevice;
import androidx.test.uiautomator.UiObject;
import androidx.test.uiautomator.UiObject2;
import androidx.test.uiautomator.UiObjectNotFoundException;
import androidx.test.uiautomator.UiScrollable;
import androidx.test.uiautomator.UiSelector;
import androidx.test.uiautomator.Until;

import java.io.File;

import static androidx.test.core.app.ApplicationProvider.getApplicationContext;
import static androidx.test.platform.app.InstrumentationRegistry.getInstrumentation;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertThat;

public class Utils {

    private static final String TAG = "Utils";


    final static private String IMAGE_DIR = "/sdcard/Screenshots/";

    /**
     * Uses package manager to find the package name of the device launcher. Usually this package
     * is "com.android.launcher" but can be different at times. This is a generic solution which
     * works on all platforms.`
     */
    public static String getLauncherPackageName() {
        // Create launcher Intent
        final Intent intent = new Intent(Intent.ACTION_MAIN);
        intent.addCategory(Intent.CATEGORY_HOME);

        // Use PackageManager to get the launcher package name
        PackageManager pm = getApplicationContext().getPackageManager();
        ResolveInfo resolveInfo = pm.resolveActivity(intent, PackageManager.MATCH_DEFAULT_ONLY);
        return resolveInfo.activityInfo.packageName;
    }

    public static UiDevice init() {
        // Initialize UiDevice instance
        return UiDevice.getInstance(getInstrumentation());
    }

    public static void WaitForLauncher(UiDevice mDevice, int launchTimeout) {
        // Wait for launcher
        final String launcherPackage = Utils.getLauncherPackageName();
        assertThat(launcherPackage, notNullValue());
        mDevice.wait(Until.hasObject(By.pkg(launcherPackage).depth(0)), launchTimeout);
    }

    public static void startMainActivityFromHomeScreen(UiDevice mDevice, String paramPackage, int launchTimeout) {

        // Start from the home screen
        mDevice.pressHome();

        WaitForLauncher(mDevice, launchTimeout);

        // Launch the tested app
        Context context = getApplicationContext();
        final Intent intent = context.getPackageManager().getLaunchIntentForPackage(paramPackage);
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);    // Clear out any previous instances
        context.startActivity(intent);

        // Wait for the app to appear
        mDevice.wait(Until.hasObject(By.pkg(paramPackage).depth(0)), launchTimeout);
    }

    public static void openAppMenu(UiDevice mDevice, int launchTimeout) {

        // Start from the home screen
        mDevice.pressHome();

        WaitForLauncher(mDevice, launchTimeout);

        mDevice.swipe(mDevice.getDisplayWidth() / 2, mDevice.getDisplayHeight(), mDevice.getDisplayWidth() / 2, 0, 55);
    }

    public static void goBackHome(UiDevice mDevice) {
        // Go back to the home screen
        mDevice.pressHome();
    }

    public static void sleep(UiDevice mDevice, long delay) {
        try {
            Thread.sleep(delay);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }


    /**
     * Select a settings items and perform scroll if needed to find it.
     *
     * @param name
     */
    private static boolean selectSettingsFor(String name) {
        try {
            UiScrollable appsSettingsList = new UiScrollable(new UiSelector().className("android.support.v7.widget.RecyclerView"));
            UiObject obj = appsSettingsList.getChildByText(new UiSelector().className(android.widget.TextView.class.getName()), name);
            obj.click();
        } catch (UiObjectNotFoundException e) {
            return false;
        }
        return true;
    }

    public static void deleteApp(UiDevice mDevice, String applicationName, int launchTimeout) {

        openAppMenu(mDevice, launchTimeout);

        UiObject2 appIcon = mDevice.wait(Until.findObject(By.text(applicationName)), 1000);
        assertNotNull(appIcon);
        appIcon.click(2000);

        // Click on the OK button if exists of on the image
        UiObject2 infoMenu = mDevice.wait(Until.findObject(By.text("Infos sur l'appli")), 1000);
        if (infoMenu == null) {
            UiObject2 infoImage = mDevice.wait(Until.findObject(By.desc("Infos sur l'appli")), 3000);
            infoImage.click();
        } else {
            infoMenu.click();
        }

        // Click on the clean data button
        mDevice.wait(Until.findObject(By.text("DÉSINSTALLER")), 3000).click();

        // Click on the OK button
        mDevice.wait(Until.findObject(By.text("OK")), 3000).click();

        // Go back to home screen
        mDevice.pressHome();
    }

    public static void cleanData(UiDevice mDevice, String applicationName, int launchTimeout) {

        // Start from the home screen
        mDevice.pressHome();

        WaitForLauncher(mDevice, launchTimeout);

        UiObject2 appIcon = mDevice.wait(Until.findObject(By.text(applicationName)), 1000);
        assertNotNull("appIcon not found", appIcon);
        appIcon.click(2000);

        // Click on the OK button if exists of on the image
        UiObject2 infoMenu = mDevice.wait(Until.findObject(By.text("Infos sur l'appli")), 1000);
        if (infoMenu == null) {
            UiObject2 infoImage = mDevice.wait(Until.findObject(By.desc("Infos sur l'appli")), 3000);
            infoImage.click();
        } else {
            infoMenu.click();
        }

        // Click on the Stockage menu
        // Add .res("android:id/title") to avoid click on Stockage in Autorisation item
        mDevice.wait(Until.findObject(By.text("Espace de stockage et cache").res("android:id/title")), 3000).click();

        // Click on the clean data button
        mDevice.wait(Until.findObject(By.text("EFFACER LES DONNÉES")), 3000).click();

        // Click on the OK button
        mDevice.wait(Until.findObject(By.text("OK")), 3000).click();

        UiObject2 emptyLabel = mDevice.wait(Until.findObject(By.text("0 octet(s)")), 1000);
        assertNotNull(emptyLabel);

        mDevice.pressBack();

        // Click on the Stockage menu
        //mDevice.wait(Until.findObject(By.text("Autorisations")), 3000).click();

        //mDevice.wait(Until.findObject(By.text("Position")), 3000).click();

        // Go back to home screen
        mDevice.pressHome();
    }

    public static void setWiFi(UiDevice mDevice, Boolean activate) {
        mDevice.pressHome();
        mDevice.openNotification();

        UiObject2 wifiMenu = mDevice.wait(Until.findObject(By.descStartsWith("Wi-Fi")), 3000);

        // Actually activated
        if ("Activé".equals(wifiMenu.getText())) {
            if (activate) {
                // Do nothing cause it's already activated
            } else {
                wifiMenu.click();
                // Wait for activation
                wifiMenu.wait(Until.findObject(By.descStartsWith("Wi-Fi,Signal Wi-Fi")), 10000);
            }
        } else {
            if (activate) {
                wifiMenu.click();
                // Wait for desactivation
                wifiMenu.wait(Until.checked(!wifiMenu.isChecked()), 10000);
            } else {
                // Do nothing cause it's already activated
            }
        }

        mDevice.pressBack();
    }

    public static void takeScreenShot(UiDevice mDevice, String fileName) {
        if (fileName == null || fileName.isEmpty()) {
            Log.e(TAG, "fileName is empty = " + fileName);
            return;
        }
        File imageDir = new File(IMAGE_DIR);
        if (!imageDir.exists()) {
            imageDir.mkdir();
        }
        File imageName = new File(IMAGE_DIR + fileName + ".png");
        boolean result = mDevice.takeScreenshot(imageName);
        System.out.println("Screenshot #" + imageName.getAbsolutePath());
        System.out.println("Screenshot result: " + Boolean.toString(result));
    }
}
