package com.rosetta.messenger.benchmark

import android.content.Intent
import androidx.benchmark.macro.CompilationMode
import androidx.benchmark.macro.FrameTimingMetric
import androidx.benchmark.macro.MacrobenchmarkScope
import androidx.benchmark.macro.StartupMode
import androidx.benchmark.macro.StartupTimingMetric
import androidx.benchmark.macro.junit4.MacrobenchmarkRule
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.filters.LargeTest
import androidx.test.uiautomator.By
import androidx.test.uiautomator.Direction
import androidx.test.uiautomator.UiObject2
import androidx.test.uiautomator.Until
import org.junit.Rule
import org.junit.Test
import org.junit.runner.RunWith

@RunWith(AndroidJUnit4::class)
@LargeTest
class AppMacrobenchmark {

    @get:Rule
    val benchmarkRule = MacrobenchmarkRule()

    private val appPackage = "com.rosetta.messenger"
    private val searchTriggers = listOf("Search", "search", "Поиск", "поиск", "Найти", "найти")
    private val runtimePermissions = listOf(
        "android.permission.POST_NOTIFICATIONS",
        "android.permission.CAMERA",
        "android.permission.RECORD_AUDIO",
        "android.permission.READ_MEDIA_IMAGES",
        "android.permission.READ_MEDIA_VIDEO",
        "android.permission.BLUETOOTH_CONNECT"
    )

    @Test
    fun coldStartup() {
        benchmarkRule.measureRepeated(
            packageName = appPackage,
            metrics = listOf(StartupTimingMetric(), FrameTimingMetric()),
            compilationMode = CompilationMode.Partial(),
            startupMode = StartupMode.COLD,
            iterations = 1,
            setupBlock = {
                grantRuntimePermissions()
                pressHome()
            }
        ) {
            launchMainActivity()
            device.waitForIdle()
        }
    }

    @Test
    fun chatListScroll() {
        benchmarkRule.measureRepeated(
            packageName = appPackage,
            metrics = listOf(FrameTimingMetric()),
            compilationMode = CompilationMode.Partial(),
            iterations = 1,
            setupBlock = {
                prepareUi()
            }
        ) {
            val list = device.findObject(By.scrollable(true)) ?: return@measureRepeated
            repeat(2) {
                list.safeScroll(Direction.DOWN, 1.0f)
                device.waitForIdle()
                list.safeScroll(Direction.UP, 1.0f)
                device.waitForIdle()
            }
        }
    }

    @Test
    fun searchFlow() {
        benchmarkRule.measureRepeated(
            packageName = appPackage,
            metrics = listOf(FrameTimingMetric()),
            compilationMode = CompilationMode.Partial(),
            iterations = 1,
            setupBlock = {
                prepareUi()
            }
        ) {
            if (!openSearchInput()) return@measureRepeated

            val input = device.wait(Until.findObject(By.clazz("android.widget.EditText")), 1_500)
                ?: return@measureRepeated

            input.text = "rosetta"
            device.waitForIdle()

            device.findObject(By.scrollable(true))?.safeScroll(Direction.DOWN, 0.7f)
            device.waitForIdle()

            device.pressBack()
            device.waitForIdle()
        }
    }

    private fun MacrobenchmarkScope.prepareUi() {
        grantRuntimePermissions()
        pressHome()
        launchMainActivity()
        device.waitForIdle()
        device.wait(Until.hasObject(By.pkg(appPackage).depth(0)), 3_000)
    }

    private fun MacrobenchmarkScope.openSearchInput(): Boolean {
        if (device.hasObject(By.clazz("android.widget.EditText"))) return true

        for (label in searchTriggers) {
            val node = device.findObject(By.descContains(label)) ?: device.findObject(By.textContains(label))
            if (node != null) {
                node.click()
                device.waitForIdle()
                if (device.wait(Until.hasObject(By.clazz("android.widget.EditText")), 1_000)) {
                    return true
                }
            }
        }

        return device.hasObject(By.clazz("android.widget.EditText"))
    }

    private fun UiObject2.safeScroll(direction: Direction, percent: Float) {
        runCatching { scroll(direction, percent) }
    }

    private fun MacrobenchmarkScope.grantRuntimePermissions() {
        runtimePermissions.forEach { permission ->
            runCatching {
                device.executeShellCommand("pm grant $appPackage $permission")
            }
        }
    }

    private fun MacrobenchmarkScope.launchMainActivity() {
        val intent = Intent(Intent.ACTION_MAIN).apply {
            addCategory(Intent.CATEGORY_LAUNCHER)
            setClassName(appPackage, "$appPackage.MainActivity")
            addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
        }
        startActivityAndWait(intent)
    }
}
