package com.example.modifier

import android.accessibilityservice.AccessibilityServiceInfo
import android.content.Context
import android.content.pm.PackageManager
import android.text.TextUtils
import android.util.Log
import android.view.accessibility.AccessibilityManager
import androidx.core.app.ActivityCompat
import com.example.modifier.http.ktorClient
import com.example.modifier.service.ModifierService
import io.ktor.client.request.head
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.coroutineScope
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import java.time.ZoneId
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.util.Locale

private const val TAG = "Modifier"
suspend fun shellRun(vararg commands: String): Pair<String, String> {
    var output = ""
    var error = ""
    Log.i(TAG, "shellRun: \t${commands.joinToString("\n\t\t\t")}")
    withContext(Dispatchers.IO) {
        val p = ProcessBuilder("su", "-M").start()
        p.outputStream.bufferedWriter().use { writer ->
            commands.forEach { command ->
                writer.write(command)
                writer.newLine()
                writer.flush()
            }
        }
        coroutineScope {
            launch {
                p.inputStream.bufferedReader().useLines {
                    it.forEach {
                        output += it + "\n"
                        Log.i(TAG, "shellRunOut: $it")
                    }
                }
            }
            launch {
                p.errorStream.bufferedReader().useLines {
                    it.forEach {
                        error += it + "\n"
                        Log.e(TAG, "shellRunErr: $it")
                    }
                }
            }
        }
        p.waitFor()
    }
    return Pair(output, error)
}

fun getContext(): Context? {
    try {
        val activityThreadClass = Class.forName("android.app.ActivityThread")
        val currentActivityThreadMethod = activityThreadClass.getMethod("currentActivityThread")
        currentActivityThreadMethod.isAccessible = true
        val currentActivityThread = currentActivityThreadMethod.invoke(null)
        val getApplicationMethod = activityThreadClass.getMethod("getApplication")
        getApplicationMethod.isAccessible = true
        return getApplicationMethod.invoke(currentActivityThread) as Context
    } catch (e: java.lang.Exception) {
        e.printStackTrace()
    }
    return null
}

suspend fun hasRootAccess(): Boolean {
    var rootAccess = false
    try {
        val (output, _) = shellRun("echo \"imrooted\"")
        if (output.contains("imrooted")) {
            rootAccess = true
        }
    } catch (e: Exception) {
        e.printStackTrace()
    }
    return rootAccess
}

fun hasPermission(permission: String): Boolean {
    return ActivityCompat.checkSelfPermission(
        getContext()!!,
        permission
    ) == PackageManager.PERMISSION_GRANTED
}

fun isAccessibilityEnabled(): Boolean {
    val context = getContext()!!
    val am = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
    val enabledServices =
        am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK)

    for (enabledService in enabledServices) {
        Log.i(
            TAG,
            "Enabled service: " + enabledService.resolveInfo.serviceInfo.packageName + "/" + enabledService.resolveInfo.serviceInfo.name
        )
        val enabledServiceInfo = enabledService.resolveInfo.serviceInfo
        if (enabledServiceInfo.packageName == context.packageName && enabledServiceInfo.name == ModifierService.NAME) return true
    }

    return false
}

suspend fun enableAccessibility(): Boolean {
    if (isAccessibilityEnabled()) return true
    val context = getContext()!!
    val am = context.getSystemService(Context.ACCESSIBILITY_SERVICE) as AccessibilityManager
    val enabledServices =
        am.getEnabledAccessibilityServiceList(AccessibilityServiceInfo.FEEDBACK_ALL_MASK)

    val names: MutableList<String?> = ArrayList()
    for (enabledService in enabledServices) {
        names.add(enabledService.resolveInfo.serviceInfo.packageName + "/" + enabledService.resolveInfo.serviceInfo.name)
    }
    names.add(context.packageName + "/" + ModifierService.NAME)

    try {
        shellRun(
            "settings put secure enabled_accessibility_services " + TextUtils.join(":", names),
            "settings put secure accessibility_enabled 1"
        )
        return true
    } catch (e: java.lang.Exception) {
        e.printStackTrace()
    }
    return false
}

suspend fun enableOverlay() {
    try {
        shellRun("appops set " + BuildConfig.APPLICATION_ID + " SYSTEM_ALERT_WINDOW allow")
    } catch (e: java.lang.Exception) {
        e.printStackTrace()
    }
}

suspend fun syncTime() {
    try {
        Log.i("Modifier", "syncTime: start")
        val response = ktorClient("").head("http://www.baidu.com")
        val dateHeader = response.headers["Date"]
        val date = ZonedDateTime.parse(
            dateHeader,
            DateTimeFormatter.ofPattern("EEE, dd MMM yyyy HH:mm:ss z", Locale.ENGLISH)
        )
        // convert to Asia/Shanghai
        val dateInZone = date.withZoneSameInstant(ZoneId.of("Asia/Shanghai"))
        Log.i(
            TAG,
            "CurrentTime from Baidu: ${dateInZone.format(DateTimeFormatter.ISO_DATE_TIME)}"
        )
        shellRun(
            "settings put system time_12_24 24",
            "settings put global auto_time 0",
            "settings put global auto_time_zone 0",
            "setprop persist.sys.timezone Asia/Shanghai",
            "date \"${dateInZone.format(DateTimeFormatter.ofPattern("MMddHHmmyyyy.ss"))}\""
        )
    } catch (e: Exception) {
        Log.e(TAG, "Error SyncTime", e)
    }
}