package net.zoneland.x.bpm.mobile.v1.zoneXBPM.utils

import android.os.Build
import android.util.Log
import java.io.BufferedReader
import java.io.BufferedWriter
import java.io.ByteArrayOutputStream
import java.io.DataOutputStream
import java.io.File
import java.io.FileInputStream
import java.io.FileOutputStream
import java.io.InputStreamReader
import java.io.OutputStreamWriter

/**
 * Created by fancyLou on 2023-09-01.
 * Copyright © 2023 android. All rights reserved.
 */

object CheckRoot {
    private val LOG_TAG = CheckRoot::class.java.name

    /**
     * 手机系统 是否已经 root
     */
    fun isDeviceRooted(): Boolean {
        if (checkDeviceDebuggable()) {
            return true
        } //check buildTags
        if (checkSuperuserApk()) {
            return true
        } //Superuser.apk
        //if (checkRootPathSU()){return true;}//find su in some path
        //if (checkRootWhichSU()){return true;}//find su use 'which'
        if (checkBusybox()) {
            return true
        } //find su use 'which'
        if (checkAccessRootData()) {
            return true
        } //find su use 'which'
        return checkGetRootAuth() //exec su
    }

    private fun checkDeviceDebuggable(): Boolean {
        val buildTags = Build.TAGS
        if (buildTags != null && buildTags.contains("test-keys")) {
            Log.i(LOG_TAG, "buildTags=$buildTags")
            return true
        }
        return false
    }

    private fun checkSuperuserApk(): Boolean {
        try {
            val file = File("/system/app/Superuser.apk")
            if (file.exists()) {
                Log.i(LOG_TAG, "/system/app/Superuser.apk exist")
                return true
            }
        } catch (e: Exception) {
        }
        return false
    }

    @Synchronized
    fun checkGetRootAuth(): Boolean {
        var process: Process? = null
        var os: DataOutputStream? = null
        return try {
            Log.i(LOG_TAG, "to exec su")
            process = Runtime.getRuntime().exec("su")
            os = DataOutputStream(process.outputStream)
            os.writeBytes("exit\n")
            os.flush()
            val exitValue = process.waitFor()
            Log.i(LOG_TAG, "exitValue=$exitValue")
            exitValue == 0
        } catch (e: Exception) {
            Log.i(
                LOG_TAG, "Unexpected error - Here is what I know: "
                        + e.message
            )
            false
        } finally {
            try {
                os?.close()
                process!!.destroy()
            } catch (e: Exception) {
                e.printStackTrace()
            }
        }
    }

    @Synchronized
    fun checkBusybox(): Boolean {
        return try {
            Log.i(LOG_TAG, "to exec busybox df")
            val strCmd = arrayOf("busybox", "df")
            val execResult = executeCommand(strCmd)
            if (execResult != null) {
                Log.i(LOG_TAG, "execResult=$execResult")
                true
            } else {
                Log.i(LOG_TAG, "execResult=null")
                false
            }
        } catch (e: Exception) {
            Log.i(
                LOG_TAG, "Unexpected error - Here is what I know: "
                        + e.message
            )
            false
        }
    }

    private fun executeCommand(shellCmd: Array<String>?): ArrayList<String?>? {
        var line: String? = null
        val fullResponse = ArrayList<String?>()
        var localProcess: Process? = null
        localProcess = try {
            Log.i(LOG_TAG, "to shell exec which for find su :")
            Runtime.getRuntime().exec(shellCmd)
        } catch (e: Exception) {
            return null
        }
        val out = BufferedWriter(OutputStreamWriter(localProcess!!.outputStream))
        val `in` = BufferedReader(InputStreamReader(localProcess.inputStream))
        try {
            while (`in`.readLine().also { line = it } != null) {
                Log.i(LOG_TAG, "–> Line received: $line")
                fullResponse.add(line)
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        Log.i(LOG_TAG, "–> Full response was: $fullResponse")
        return fullResponse
    }

    @Synchronized
    fun checkAccessRootData(): Boolean {
        return try {
            Log.i(LOG_TAG, "to write /data")
            val fileContent = "test_ok"
            val writeFlag = writeFile("/data/su_test", fileContent)
            if (writeFlag) {
                Log.i(LOG_TAG, "write ok")
            } else {
                Log.i(LOG_TAG, "write failed")
            }
            Log.i(LOG_TAG, "to read /data")
            val strRead = readFile("/data/su_test")
            Log.i(LOG_TAG, "strRead=$strRead")
            fileContent == strRead
        } catch (e: Exception) {
            Log.i(
                LOG_TAG, "Unexpected error - Here is what I know: "
                        + e.message
            )
            false
        }
    }

    //写文件
    private fun writeFile(fileName: String?, message: String): Boolean {
        return try {
            val fout = FileOutputStream(fileName)
            val bytes = message.toByteArray()
            fout.write(bytes)
            fout.close()
            true
        } catch (e: Exception) {
            e.printStackTrace()
            false
        }
    }

    //读文件
    private fun readFile(fileName: String): String? {
        val file = File(fileName)
        return try {
            val fis = FileInputStream(file)
            val bytes = ByteArray(1024)
            val bos = ByteArrayOutputStream()
            var len: Int
            while (fis.read(bytes).also { len = it } > 0) {
                bos.write(bytes, 0, len)
            }
            val result = String(bos.toByteArray())
            Log.i(LOG_TAG, result)
            result
        } catch (e: Exception) {
            e.printStackTrace()
            null
        }
    }
}