package com.duben.microtribe.utils.rxutil

import android.annotation.SuppressLint
import android.app.Activity
import android.app.KeyguardManager
import android.content.Context
import android.content.ContextWrapper
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Configuration
import android.graphics.Bitmap
import android.graphics.Canvas
import android.graphics.Rect
import android.graphics.drawable.Drawable
import android.os.Build
import android.os.Looper
import android.util.DisplayMetrics
import android.util.Log
import android.view.View
import android.view.WindowManager
import androidx.annotation.AttrRes
import androidx.annotation.ColorInt
import androidx.annotation.ColorRes
import androidx.core.content.ContextCompat
import androidx.fragment.app.Fragment
import com.duben.microtribe.BuildConfig
import com.duben.microtribe.MintsApplication
import java.text.SimpleDateFormat
import java.util.*
import kotlin.math.abs


private const val TAG = "core.utils.common"

@Suppress("unused", "DEPRECATION", "MemberVisibilityCanBePrivate")
object CommonUtils {
    fun trueOrThrow(expression: Boolean) {
        if (BuildConfig.DEBUG) {
            trueOrThrow(expression, "Error!")
        }
    }

    fun mainThreadOrThrow() {
        if (BuildConfig.DEBUG) {
            trueOrThrow(
                    Thread.currentThread() === Looper.getMainLooper().thread,
                    "Not on main thread. current = " + Thread.currentThread()
            )
        }
    }

    fun workerThreadOrThrow() {
        if (BuildConfig.DEBUG) {
            trueOrThrow(
                    Thread.currentThread() !== Looper.getMainLooper().thread,
                    "On main thread. current = " + Thread.currentThread()
            )
        }
    }

    fun trueOrThrow(expression: Boolean, message: String?) {
        if (BuildConfig.DEBUG) {
            trueOrThrow(expression, message, null)
        }
    }

    fun trueOrThrow(expression: Boolean, e: Exception?) {
        if (BuildConfig.DEBUG) {
            trueOrThrow(expression, "Error!", e)
        }
    }

    fun trueOrThrow(expression: Boolean, message: String?, e: Exception?) {
        if (BuildConfig.DEBUG) {
            if (!expression) {
                throw IllegalStateException(message, e)
            }
        }
    }

    fun drawable2Bitmap(icon: Drawable, size: Int): Bitmap {
        val bmp = Bitmap.createBitmap(size, size, Bitmap.Config.ARGB_8888)
        val c = Canvas(bmp)
        val drawable = icon.mutate()
        try {
            drawable.setBounds(0, 0, size, size)
        } catch (e: Exception) {
            if (BuildConfig.DEBUG) Log.e(TAG, "drawable2Bitmap: ", e)
        }
        drawable.draw(c)
        return bmp
    }

    /**
     * @return true if succeed.
     */
    @JvmStatic
    fun startActivitySafe(context: Context, intent: Intent): Boolean {
        if (BuildConfig.DEBUG) Log.d(TAG, "startActivitySafe() called  with: context = [$context], intent = [$intent]")

        try {
            if (context !is Activity) {
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
            }
            context.startActivity(intent)
            return true
        } catch (e: java.lang.Exception) {
            if (BuildConfig.DEBUG) Log.e(TAG, "ERROR", e)
        }

        return false
    }

    /**
     * @return true if succeed.
     */
    @JvmStatic
    fun startActivitiesSafe(context: Context, intents: Array<Intent>): Boolean {
        try {
            if (context !is Activity) {
                for (intent in intents) {
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                }
            }
            context.startActivities(intents)
            return true
        } catch (e: java.lang.Exception) {
            if (BuildConfig.DEBUG) Log.e(TAG, "ERROR", e)
        }

        return false
    }

    fun isViewContextStable(fragment: Fragment): Boolean {
        return isContextStable(fragment)/* && fragment is AbsFragment && fragment.isViewCreated*/
    }

    fun isContextStable(fragment: Fragment): Boolean {
        return (!fragment.isDetached && fragment.activity != null && !fragment.activity!!.isFinishing)
    }

    fun isContextStable(context: Activity): Boolean {
        return !context.isFinishing
    }

    fun isTimeout(lastTimeStamp: Long, duration: Long): Boolean {
        val now = System.currentTimeMillis()
        val pastMs = now - lastTimeStamp
        return duration > 0 && (pastMs < 0 || pastMs > duration)
    }

    fun isEmpty(string: String?): Boolean {
        return string == null || string.isEmpty()
    }


    private val tempBounds: Rect = Rect()

    fun drawable2BitmapForced(drawable: Drawable, sizePixel: Int): Bitmap {
        val bitmap = Bitmap.createBitmap(sizePixel, sizePixel, Bitmap.Config.ARGB_8888)
        val canvas = Canvas(bitmap)
        val drawableMutated = drawable.mutate()
        val bounds: Rect = drawableMutated.bounds
        tempBounds.set(bounds)
        drawableMutated.setBounds(0, 0, sizePixel, sizePixel)
        drawableMutated.draw(canvas)
        drawableMutated.bounds = bounds
        return bitmap
    }


    fun stringToInt(string: String?, dafault: Int): Int {
        try {
            return if (string == null || string.isEmpty()) dafault else string.toInt()
        } catch (e: java.lang.Exception) {
            if (BuildConfig.DEBUG) Log.e(TAG, "ERROR", e)
        }
        return dafault
    }

    private var versionCode: Int? = null
    private var versionName: String? = null

    /* 获取本地软件版本号​
     */
    fun getSelfVersionCode(): Int {
        if (versionCode != null) {
            return versionCode!!
        }
        var localVersion = 0
        try {
            val ctx: Context = MintsApplication.getContext()
            val packageInfo = ctx.applicationContext
                    .packageManager
                    .getPackageInfo(ctx.packageName, 0)
            @Suppress("DEPRECATION")
            localVersion = packageInfo.versionCode
            versionCode = localVersion
            if (BuildConfig.DEBUG) Log.d("TAG", "Vc: $localVersion")
        } catch (e: Throwable) {
            if (BuildConfig.DEBUG) Log.e(TAG, "ERROR", e)
        }
        return localVersion
    }

    /**
     * 获取本地软件版本号名称
     */
    fun getSelfVersionName(): String? {
        if (null != versionName) {
            return versionName
        }
        var localVersion = ""
        try {
            val ctx: Context = MintsApplication.getContext()
            val packageInfo = ctx.applicationContext
                    .packageManager
                    .getPackageInfo(ctx.packageName, 0)
            localVersion = packageInfo.versionName
            versionName = localVersion
            if (BuildConfig.DEBUG) Log.d("TAG", "Vn: $localVersion")
        } catch (e: Throwable) {
            if (BuildConfig.DEBUG) Log.e(TAG, "ERROR", e)
        }
        return localVersion
    }

    fun getRealDisplayMetrics(context: Context): DisplayMetrics {
        val outMetrics = DisplayMetrics()
        try {
            val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
            windowManager.defaultDisplay.getRealMetrics(outMetrics)
        } catch (e: java.lang.Exception) {
            if (BuildConfig.DEBUG) Log.e(TAG, "getRealDisplayMetrics: ERROR", e)
            outMetrics.widthPixels = 100
            outMetrics.heightPixels = 100

        }
        return outMetrics
    }

    fun getContentDisplayMetrics(context: Context): DisplayMetrics {
        val outMetrics = DisplayMetrics()
        try {
            val windowManager = context.getSystemService(Context.WINDOW_SERVICE) as WindowManager
            windowManager.defaultDisplay.getMetrics(outMetrics)
        } catch (e: java.lang.Exception) {
            if (BuildConfig.DEBUG) Log.e(TAG, "getRealDisplayMetrics: ERROR", e)
            outMetrics.widthPixels = 100
            outMetrics.heightPixels = 100

        }
        return outMetrics
    }


    @ColorInt
    fun getColorAttribution(context: Context, @AttrRes attrId: Int, @ColorRes defaultColorId: Int): Int {
        val textColorAttr = intArrayOf(attrId)
        val indexOfAttrTextSize = 0
        val a = context.obtainStyledAttributes(textColorAttr)
        val attrColor = a.getColor(indexOfAttrTextSize, context.resources.getColor(defaultColorId))
        a.recycle()
        return attrColor
    }

    fun isBrandNewUser(context: Context): Boolean {
        if (BuildConfig.DEBUG) Log.d(TAG, "isBrandNewUser() called with: context = [$context]")
        try {
            val applicationContext = context.applicationContext
            val packageManager = applicationContext.packageManager
            val packageInfo = packageManager.getPackageInfo(context.packageName, 0)
            val firstInstallTime = packageInfo.firstInstallTime
            val lastUpdateTime = packageInfo.lastUpdateTime
            if (BuildConfig.DEBUG) Log.d(TAG, "isBrandNewUser() first install time : $firstInstallTime last update time :$lastUpdateTime")
            // don't tell me someone updated the app within 3 secs.
            // we just ignore such kind of stupidity!
            return lastUpdateTime <= 0 || abs(firstInstallTime - lastUpdateTime) < 3000
        } catch (e: java.lang.Exception) {
            if (BuildConfig.DEBUG) Log.e(TAG, "isBrandNewUser: ERROR", e)
        }
        return false
    }

    /**
     * Checks for granted permission but by a single string (single permission)
     *
     * @param permission
     * @return boolean
     */
    fun checkPermissionsGranted(context: Context, permission: String): Boolean {
        return (Build.VERSION.SDK_INT < Build.VERSION_CODES.M
                || ContextCompat.checkSelfPermission(
                context, permission
        )
                == PackageManager.PERMISSION_GRANTED)
    }

    /**
     * Check for permissions by a given list
     *
     * @param permissions
     * @return boolean
     */
    fun checkPermissionsGranted(context: Context, permissions: Array<String>): Boolean {
        for (permission in permissions) {
            if (!checkPermissionsGranted(context, permission)) {
                return false
            }
        }
        return true
    }

    /**
     * Check for permissions by a given list
     *
     * @param grantResults
     * @return boolean
     */
    fun checkPermissionsGranted(grantResults: IntArray): Boolean {
        if (Build.VERSION.SDK_INT < Build.VERSION_CODES.M) {
            return true
        }
        for (result in grantResults) {
            if (result == PackageManager.PERMISSION_DENIED) return false
        }
        return true
    }

    @JvmStatic
    fun getActivity(view: View): Activity? {
        var context = view.context
        while (context is ContextWrapper) {
            if (context is Activity) {
                return context
            }
            context = context.baseContext
        }
        return null
    }

    fun hasSystemLockScreen(context: Context): Boolean {
        try {
            val km = context.getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
                km.isDeviceSecure
            } else {
                km.isKeyguardSecure
            }
        } catch (e: java.lang.Exception) {
            if (BuildConfig.DEBUG) Log.e(TAG, "isScreenOff: ERROR", e)

        }

        return false
    }

    fun getLang(): String {
        try {
            return Locale.getDefault().language
        } catch (e: java.lang.Exception) {
            Log.e(TAG, "ERROR", e)
        }
        return Locale.ENGLISH.language
    }


//    fun valueOfFirstDayOrOther(valueWithinFirstDay: Long, valueOutOfFirstDay: Long): Long = if (SystemUtilsJava.isNotFirstDayOfInstall(BaseApp.instance)) {
//        valueOutOfFirstDay
//    } else {
//        valueWithinFirstDay
//    }

    fun isPortrait(): Boolean {
        return try {
            MintsApplication.getContext().resources.configuration.orientation == Configuration.ORIENTATION_PORTRAIT
        } catch (e: Exception) {
            if (BuildConfig.DEBUG) Log.e(TAG, "isPortrait: ERROR", e)
            false
        }
    }

    private const val FORMAT_DEFAULT = "yyyy-MM-dd"
    @SuppressLint("ConstantLocale")
    private val formatter = SimpleDateFormat(FORMAT_DEFAULT, Locale.getDefault())
    fun isFirstDayInstall(
        installTime: Long
    ): Boolean {
        val install = formatter.format(Date(installTime))
        val now = formatter.format(Date(System.currentTimeMillis()))
        val result = install == now
        if (BuildConfig.DEBUG) Log.d(TAG, "isFirstDayInstall() returned: result = $result, install = $install, now = $now")
        return result
    }

    private val random = Random(System.currentTimeMillis())

    fun checkRateInt(readInt: Int): Boolean {
        if (BuildConfig.DEBUG) {
            if (readInt < 0 || readInt > 100) {
                throw RuntimeException("BUG!")
            }
        }

        val rand = random.nextInt(101)
        return rand in 1 until readInt
    }
}