package com.seatel.mobilehall.util

import android.app.Activity
import android.content.Context
import android.content.Intent
import android.content.pm.PackageManager
import android.content.res.Resources
import android.graphics.Color
import android.os.Build
import android.provider.Settings
import android.text.Html
import android.text.Spanned
import android.text.TextUtils
import android.text.format.DateFormat
import android.util.DisplayMetrics
import android.util.Log
import android.view.View
import android.view.inputmethod.InputMethodManager
import android.widget.TextView
import androidx.annotation.RequiresApi
import androidx.core.content.ContextCompat
import com.seatel.mobilehall.BuildConfig
import com.seatel.mobilehall.R
import com.seatel.mobilehall.data.prefs.LanguagePreference
import com.seatel.mobilehall.data.prefs.SeatelSharePreferences
import com.seatel.mobilehall.util.customview.CustomTextView
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.math.RoundingMode
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import java.text.*
import java.time.ZonedDateTime
import java.time.format.DateTimeFormatter
import java.util.*
import java.util.regex.Pattern
import javax.crypto.Mac
import kotlin.experimental.and

/**
 * Created by Danny on 11/15/2017.
 *
 *
 */
class SeatelUtils {
    //get phone Screen size
    fun getScreenSize(activity: Activity): DisplayMetrics {
        val displayMetrics = DisplayMetrics()
        activity.windowManager.defaultDisplay.getMetrics(displayMetrics)
        return displayMetrics
    }

    fun generateHashkey(context: Context) {
        try {
            val info = context.packageManager.getPackageInfo(
                "com.seatel.mobilehall",
                PackageManager.GET_SIGNATURES
            )
            for (signature in info.signatures) {
                val md = MessageDigest.getInstance("SHA")
                md.update(signature.toByteArray())
                Log.d(
                    "KeyHash:",
                    android.util.Base64.encodeToString(md.digest(), android.util.Base64.DEFAULT)
                )
            }
        } catch (ignored: PackageManager.NameNotFoundException) {
        } catch (ignored: NoSuchAlgorithmException) {
        }
    }

    companion object {
        private var toolBarHeight = -1
        fun darkenStatusBar(activity: Activity, color: Int) {
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                activity.window.statusBarColor = darkenColor(
                    ContextCompat.getColor(
                        activity,
                        color
                    )
                )
            }
        }

        fun convertDpToPx(context: Context, dp: Int): Int {
            return Math.round(dp * context.resources.displayMetrics.density)
        }

        fun checkIsNoneSeatelType(typeAccount: String): Boolean {
            return TextUtils.equals(typeAccount.lowercase(Locale.getDefault()), "off-net")
        }

        fun getDisplayMetrics(context: Context): DisplayMetrics {
            val displayMetrics = DisplayMetrics()
            (context as Activity).windowManager
                .defaultDisplay
                .getMetrics(displayMetrics)
            return displayMetrics
        }

        fun pxToDp(px: Int): Int {
            return (px / Resources.getSystem().displayMetrics.density).toInt()
        }

        fun shareToSocail(context: Context?, url: String?, description: String?) {
            val intent = Intent()
            intent.action = Intent.ACTION_SEND
            intent.type = "text/plain"
            intent.putExtra(Intent.EXTRA_SUBJECT, description)
            intent.putExtra(Intent.EXTRA_TEXT, url)
            /**        context.startActivity(Intent.createChooser(intent, "Share"));
             * //        Intent shareIntent = ShareCompat.IntentBuilder.from((Activity) context)
             * //                .setType("text/plain")
             * //                .setChooserTitle("Share Data")
             * //                .setSubject("#yesseatelCNYpromo")
             * //                .setText("I have won a gift from yes seatel. https://www.yes.com.kh")
             * //                .createChooserIntent();
             * //        if(shareIntent.resolveActivity(context.getPackageManager()) != null){
             * //            ((Activity) context).startActivityForResult(shareIntent,202);
             * }
             */
        }

        fun gotoMainScreen(context: Context?) {
            if (!SeatelSharePreferences.getInstance(context!!)!!.getNoneSeatelNumber()!!) {
                //   HomeMainNonSeatelActivity.Companion.lunch(context);
            }
        }

        // Code to darken the color supplied (mostly color of toolbar)
        private fun darkenColor(color: Int): Int {
            val hsv = FloatArray(3)
            Color.colorToHSV(color, hsv)
            hsv[2] *= 0.8f
            return Color.HSVToColor(hsv)
        }

        fun setFormatcurrency(format: Any?): String {
            return try {
                NumberFormat.getCurrencyInstance(Locale("en", "US")).format(format)
            } catch (e: Exception) {
                e.printStackTrace()
                ""
            }
        }

        fun getDiscountPrice(price: Double, discount: Double): String {
            val disountCal = price * (discount / 100)
            return String.format(Locale.US, "%.2f", price - disountCal)
        }

        fun convertSecondToTime(totalSecs: Double): String {
            return "" + Math.ceil(totalSecs / 60).toInt()
        }

        fun checkPhone(str: String): String {
            var str = str
            if (!str.isEmpty()) {
                str = str.trim { it <= ' ' }.replace(" ", "")
                if (str.startsWith("0")) {
                    str = str.substring(1)
                } else if (str.startsWith("855")) {
                    str = str.substring(3)
                }
            }
            return str
        }

        fun convertSecondToDisplayFullTime(totalSecs: Double): IntArray {
            var hour = 0
            var minute = 0
            val second: Int
            var remain = totalSecs
            if (totalSecs >= 3600.00) {
                hour = (totalSecs / 3600).toInt()
                remain = totalSecs - hour * 3600
                if (remain >= 60) {
                    minute = remain.toInt() / 60
                    remain -= minute * 60
                    second = if (remain >= 60) {
                        remain.toInt() / 60
                    } else {
                        remain.toInt()
                    }
                } else {
                    second = remain.toInt()
                }
            } else if (remain >= 60) {
                minute = remain.toInt() / 60
                remain = totalSecs - minute * 60
                second = if (remain >= 60) {
                    remain.toInt() / 60
                } else {
                    remain.toInt()
                }
            } else {
                second = remain.toInt()
            }
            return intArrayOf(hour, minute, second)
        }

        //            SecretKeySpec secret_key = new SecretKeySpec(BuildConfig.CLIENT_SECRET.getBytes(), "HmacSHA256");
//            sha256_HMAC.init(secret_key);
        val signature: String
            get() = try {
                val sha256_HMAC = Mac.getInstance("HmacSHA256")
                //            SecretKeySpec secret_key = new SecretKeySpec(BuildConfig.CLIENT_SECRET.getBytes(), "HmacSHA256");
//            sha256_HMAC.init(secret_key);
                Base64.encodeBytes(
                    sha256_HMAC.doFinal(
                        BuildConfig.CLIENT_ID.toByteArray(
                            StandardCharsets.UTF_8
                        )
                    )
                )
            } catch (e: Exception) {
                e.printStackTrace()
                ""
            }

        fun getSha1Hex(clearString: String): String? {
            return try {
                val messageDigest = MessageDigest.getInstance("SHA-1")
                messageDigest.update(clearString.toByteArray(StandardCharsets.UTF_8))
                val bytes = messageDigest.digest()
                val buffer = StringBuilder()
                val c = 0xFF.toChar()
                for (b in bytes) {
                    buffer.append(((b and c.code.toByte()) + 0x100).toString(16).substring(1))
                }
                buffer.toString()
            } catch (ignored: Exception) {
                ignored.printStackTrace()
                null
            }
        }

        fun appendJSONArray(a: JSONArray?, b: JSONArray?): JSONArray? {
            try {
                if (a != null && a.length() > 0 && b != null && b.length() > 0) {
                    var data = "$a#$b"
                    data = data.replace("]#[", ",")
                    return JSONArray(data)
                } else if (a != null && a.length() > 0) {
                    return a
                } else if (b != null && b.length() > 0) {
                    return b
                }
            } catch (e: JSONException) {
                e.printStackTrace()
            }
            return null
        }

        fun optJSONArray(`object`: JSONObject, key: String?): JSONArray {
            return try {
                `object`.getJSONArray(key)
            } catch (e: Exception) {
                JSONArray()
            }
        }

        fun optJSONObject(`object`: JSONObject, vararg key: String?): JSONObject {
            var `object` = `object`
            return try {
                for (aKey in key) {
                    `object` = `object`.getJSONObject(aKey)
                }
                `object`
            } catch (e: Exception) {
                JSONObject()
            }
        }

        fun optJSONObject(`object`: JSONArray, index: Int): JSONObject {
            return try {
                `object`.getJSONObject(index)
            } catch (e: Exception) {
                JSONObject()
            }
        }

        fun checkIsPurchaseAble(price: Int): Boolean {
            return false
        }

        fun isEmailValid(email: String): Boolean {
            val regExpn = ("^(([\\w-]+\\.)+[\\w-]+|([a-zA-Z]{1}|[\\w-]{2,}))@"
                    + "((([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\\.([0-1]?"
                    + "[0-9]{1,2}|25[0-5]|2[0-4][0-9])\\."
                    + "([0-1]?[0-9]{1,2}|25[0-5]|2[0-4][0-9])\\.([0-1]?"
                    + "[0-9]{1,2}|25[0-5]|2[0-4][0-9])){1}|"
                    + "([a-zA-Z]+[\\w-]+\\.)+[a-zA-Z]{2,4})$")
            val inputStr: CharSequence = email
            val pattern = Pattern.compile(regExpn, Pattern.CASE_INSENSITIVE)
            val matcher = pattern.matcher(inputStr)
            return !matcher.matches()
        }

        fun readableFileSize(size: Long): String {
            if (size <= 0) return "0 Bytes"
            val units = arrayOf("Bytes", "KB", "MB", "GB", "TB")
            val digitGroups = (Math.log10(size.toDouble()) / Math.log10(1024.0)).toInt()
            return DecimalFormat("#,##0.#").format(
                size / Math.pow(
                    1024.0,
                    digitGroups.toDouble()
                )
            ) + " " + units[digitGroups]
        }

        fun checkIsNonSeatel(phone: String): Boolean {
            return if (phone.isEmpty()) true else !phone.startsWith("018") && !phone.startsWith("18") && !phone.startsWith(
                "85518"
            )
        }

        fun isEmailorPhone(text: String): Boolean {
            return !(text.matches("^[0-9]+(-[0-9]+)+$".toRegex()) || text.matches("[0-9]+".toRegex()))
        }

        fun isValidatePhoneFormat(PhoneNo: String): Boolean {
            var valid = false
            val Regex = "[^\\d]"
            val PhoneDigits = PhoneNo.replace(Regex.toRegex(), "")
            if (PhoneDigits.length < 13 && PhoneDigits.length > 8) {
                if (TextUtils.equals(PhoneDigits.substring(0, 1), "0") || TextUtils.equals(
                        PhoneDigits.substring(0, 3),
                        "855"
                    )
                ) {
                    valid = true
                }
                // validation successful
            }
            return valid
        }

        fun isInvalidPhoneFormatSeatelSim(PhoneNo: String): Boolean {
            var valid = true
            val Regex = "[^\\d]"
            val PhoneDigits = PhoneNo.replace(Regex.toRegex(), "")
            if (PhoneDigits.length < 13 && PhoneDigits.length > 9) {
                if (TextUtils.equals(
                        PhoneDigits.substring(0, 3),
                        "018"
                    ) && PhoneDigits.substring(3).length >= 7
                ) valid = false
            }
            return valid
        }

        fun spToPx(context: Context, sp: Float): Int {
            val scale = context.resources.displayMetrics.scaledDensity
            return (sp * scale + 0.5f).toInt()
        }

        fun getDateTimeNotification(outPutFormat: String?, date: String?): String {
            return getDateTime("yyyy-MM-dd'T'HH:mm:ss.SSSZ", outPutFormat, date)
        }

        fun getDateTime(outPutFormat: String?, date: String?): String {
            return getDateTime("dd MMM,yyyy", outPutFormat, date)
        }

        fun getDateTime(serverFormat: String?, outPutFormat: String?, date: String?): String {
            var mDateTime = ""
            try {
                // parse from server format to date  eg. format "yyyy-MM-dd hh:mm:ss" : "2018-02-22 2:52:26"
                var simpleDateFormat = SimpleDateFormat(serverFormat, Locale.getDefault())
                simpleDateFormat.timeZone = TimeZone.getTimeZone("UTC")
                val mDateServer = simpleDateFormat.parse(date)

                // parse from date to display format
                simpleDateFormat = SimpleDateFormat(outPutFormat, Locale.getDefault())
                //            simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
                mDateTime = simpleDateFormat.format(mDateServer)
            } catch (e: ParseException) {
                e.printStackTrace()
            }
            return mDateTime
        }

        fun formatDecimalNumber(value: Double, pattern: String?): String {
            val otherSymbols = DecimalFormatSymbols(Locale.getDefault())
            otherSymbols.decimalSeparator = '.'
            otherSymbols.groupingSeparator = ','
            val decimalFormat = DecimalFormat(pattern, otherSymbols)
            return decimalFormat.format(value)
        }

        fun getGenerateColorByMonths(index: Int): String {
            val colorByMonths = arrayOf(
                "#fe001a", "#04bfb8", "#bf7604", "#06b52b", "#00c0ff", "#0ac5c7",
                "#700000", "#d3b613", "#0b5f94", "#ad0d75", "#4500d0", "#6f9507"
            )
            return colorByMonths[index]
        }

        fun roundUp(value: Double): Double {
            var value = value
            val factor = Math.pow(10.0, 2.0).toLong()
            value = value * factor
            val tmp = Math.round(value)
            return tmp.toDouble() / factor
        }

        fun getPhoneFormat(phoneNumber: String): String {
            var phoneNumber = phoneNumber
            if (TextUtils.isEmpty(phoneNumber)) return phoneNumber
            if (!phoneNumber.startsWith("0")) {
                phoneNumber = "0$phoneNumber"
            }
            phoneNumber = phoneNumber.substring(0, 3) + " " + phoneNumber.substring(
                3,
                6
            ) + " " + phoneNumber.substring(6)
            phoneNumber =
                phoneNumber.substring(0, 1).replace("0", "855 - ") + phoneNumber.substring(1)
            return phoneNumber
        }

        fun getPhoneFormatWithOutCode(phoneNumber: String): String {
            var phoneNumber = phoneNumber
            if (TextUtils.isEmpty(phoneNumber)) return phoneNumber
            if (!phoneNumber.startsWith("0")) {
                phoneNumber = "0$phoneNumber"
            }
            phoneNumber = phoneNumber.substring(0, 3) + " " + phoneNumber.substring(
                3,
                6
            ) + " " + phoneNumber.substring(6)
            //        phoneNumber = phoneNumber.substring(0, 1).replace("0", "") + phoneNumber.substring(1, phoneNumber.length());
            return phoneNumber
        }

        fun milliSecondsToTimer(milliseconds: Long): String {
            var finalTimerString = ""
            val secondsString: String

            // Convert total duration into time
            val hours = (milliseconds / (1000 * 60 * 60)).toInt()
            val minutes = (milliseconds % (1000 * 60 * 60)).toInt() / (1000 * 60)
            val seconds = (milliseconds % (1000 * 60 * 60) % (1000 * 60) / 1000).toInt()
            // Add hours if there
            if (hours > 0) {
                finalTimerString = "$hours : "
            }

            // Prepending 0 to seconds if it is one digit
            secondsString = if (seconds < 10) {
                "0$seconds"
            } else {
                "" + seconds
            }
            finalTimerString = "$finalTimerString$minutes : $secondsString"

            // return timer string
            return finalTimerString
        }

        fun hideKeyboard(activity: Activity) {
            val view = activity.findViewById<View>(android.R.id.content)
            if (view != null) {
                val imm =
                    activity.getSystemService(Context.INPUT_METHOD_SERVICE) as InputMethodManager
                imm.hideSoftInputFromWindow(view.windowToken, 0)
            }
        }

        fun fromHtml(html: String?): Spanned {
            return if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                Html.fromHtml(html, Html.FROM_HTML_MODE_LEGACY)
            } else {
                Html.fromHtml(html)
            }
        }

        fun convertGbToMb(`val`: Double): Double {
            return (`val` * 1024)
        }

        fun convertMbToTb(`val`: Double): Double {
            return `val` / 1048576
        }

        fun convertMbToGb(`val`: Double): Double {
            return if (`val` >= 1024) `val` / 1024 else `val`
        }

        fun convertMbToSize(`val`: Double): String {
            val decimalFormat = DecimalFormat("#.##")
            return if (`val` >= 1048576) decimalFormat.format(`val` / 1048576) else if (`val` >= 1024) decimalFormat.format(
                `val` / 1024
            ) else decimalFormat.format(`val`)
        }

        private val c = charArrayOf('k', 'm', 'b', 't')
        fun formatNumberK(n: Double, iteration: Int): String {
            if (n < 1000) {
                return displayAmountNoDecial(n.toString() + "")
            }
            val d = n.toLong() / 100 / 10.0
            val isRound =
                d * 10 % 10 == 0.0 //true if the decimal part is equal to 0 (then it's trimmed anyway)
            return if (d < 1000) //this determines the class, i.e. 'k', 'm' etc
                (if (d > 99.9 || isRound || !isRound && d > 9.99) //this decides whether to trim the decimals
                    d.toInt() * 10 / 10 else d.toString() + "" // (int) d * 10 / 10 drops the decimal
                        ).toString() + "" + c[iteration] else formatNumberK(d, iteration + 1)
        }

        fun getTypeData(`val`: Double): String {
            return if (`val` >= 1048576) "TB" else if (`val` >= 1024) "GB" else "MB"
        }

        fun getViewLocationOnScreen(view: View): IntArray {
            val location = IntArray(2)
            view.getLocationOnScreen(location)
            return location
        }

        fun calcualateFreedomDataInput(`val`: Long): Double {
            val basePrice = 1100
            var total = ((50 * (`val` - 1) + basePrice) * `val`).toDouble()
            total = total / 1000
            return total
        }

        fun displayDataFreedomDataInput(`val`: Double): Array<String> {
            var `val` = `val`
            var typeSize = "GB"
            if (`val` >= 1024) {
                `val` = `val` / 1024
                typeSize = "TB"
            }
            val mod = `val` % `val`.toLong() // devide mod remaining
            return if (mod == 0.0) {
                arrayOf("" + `val`.toLong(), typeSize)
            } else {
                val decimalFormat = DecimalFormat("#.#")
                decimalFormat.roundingMode = RoundingMode.CEILING
                arrayOf(decimalFormat.format(`val`), typeSize)
            }
        }

        fun displayDataFreedomData(`val`: Double): String {
            val mod = `val` % `val`.toLong() // devide mod remaining
            return if (mod == 0.0) {
                "" + `val`.toInt()
            } else {
                val decimalFormat = DecimalFormat("#.#")
                decimalFormat.roundingMode = RoundingMode.CEILING
                decimalFormat.format(`val`)
            }
        }

        fun phoneNumberFormat(str: String?): String {
            var str = str ?: return ""
            if (!TextUtils.equals(str, "") && str.length > 3) {
                str = str.replace(" ", "")
                if (TextUtils.equals(str.substring(0, 3), "855")) str =
                    "0" + str.substring(3) else if (!TextUtils.equals(
                        str.substring(0, 1),
                        "0"
                    )
                ) str = "0$str"
                val sb = StringBuffer()
                sb.append(str)
                str = sb.insert(3, " ").toString()
                if (str.length > 7) str = sb.insert(7, " ").toString()
            }
            return str
        }

        fun showErrorDialog(context: Context?, error: String?) {
            SeatelAlertDialog.with(context!!, error).show()

//        AlertDialog.Builder builder = new AlertDialog.Builder(context);
//        builder.setMessage(error);
//        builder.setCancelable(false);
//
//        builder.setPositiveButton(context.getString(R.string.yes), new DialogInterface.OnClickListener() {
//
//            @Override
//            public void onClick(DialogInterface dialogInterface, int i) {
//                dialogInterface.dismiss();
//            }
//        });
//
//        builder.show();
        }

        fun getToolBarHeight(context: Context): Int {
            if (toolBarHeight > 0) {
                return toolBarHeight
            }
            val resources = context.resources
            val resourceId = resources.getIdentifier("action_bar_size", "dimen", "android")
            toolBarHeight =
                if (resourceId > 0) resources.getDimensionPixelSize(resourceId) else convertDpToPx(
                    context,
                    56
                )
            return toolBarHeight
        }

        fun toCamelCase(init: String?): String? {
            if (init == null) return null
            val ret = StringBuilder(init.length)
            for (word in init.split(" ").toTypedArray()) {
                if (!word.isEmpty()) {
                    ret.append(word.substring(0, 1).uppercase(Locale.getDefault()))
                    ret.append(word.substring(1).lowercase(Locale.getDefault()))
                }
                if (ret.length != init.length) ret.append(" ")
            }
            return ret.toString()
        }

        fun getDate(time: Long): String {
            val cal = Calendar.getInstance(Locale.ENGLISH)
            cal.timeInMillis = time
            return DateFormat.format("mmm-dd-yyyy", cal).toString()
        }

        fun getDeviceId(context: Context): String {
            return Settings.Secure.getString(context.contentResolver, Settings.Secure.ANDROID_ID)
        }

        fun getLangaugeCode(context: Context?): String? {
            return LanguagePreference.getInstance(context!!)!!.getAppSharedLanguageCodePreference()
        }

        fun setRoundAmountSize(`val`: Int): Int {
            var last = `val`.toString()
            last = last.substring(last.length - 1)
            return `val` - Integer.valueOf(last)
        }

        fun displayAmountNoDecial(str: String): String {
            if (TextUtils.isEmpty(str)) return str
            val str1 = str.substring(str.length - 2)
            return if (TextUtils.equals(str1, ".0")) str.substring(0, str.length - 2) else str
        }

        fun displayAmountNoDecial(context: Context?, str: String): String {
            if (TextUtils.isEmpty(str)) return str
            val str1 = str.substring(str.length - 2)
            return if (TextUtils.equals(str1, ".0")) str.substring(0, str.length - 2) else str
        }

        @JvmStatic
        fun translatForDialog(context: Context?, str: String?): String {
            val tem = CustomTextView(context!!)
            tem.text = str
            return tem.text.toString()
        }

        fun updateFontSizeTextView(context: Context, txtView: TextView, size: Float): Boolean {
            if (txtView.lineCount > 1) {
                txtView.textSize = context.resources.getDimension(R.dimen.small_text_size) - size
                return false
            }
            if (size == 0.5f) txtView.textSize =
                context.resources.getDimension(R.dimen.small_text_size)
            return true
        }

        fun roundInteger(context: Context?, value: Int): Int {
            var str = value.toString()
            return if (str.length > 1) {
                str = str.substring(str.length - 1)
                var round = Integer.valueOf(str)
                val main = value - round
                //            if (round >= 5)
//                round = main + 10;
//            else {
                round = main
                //            }
                round
            } else {
                value
            }
        }

        @RequiresApi(Build.VERSION_CODES.O)
        fun formatDateCoin(input: String): String {
            return try {
                val inputFormatter = DateTimeFormatter.ISO_DATE_TIME
                val outputFormatter = DateTimeFormatter.ofPattern("dd MMM yyyy", Locale.ENGLISH)
                val dateTime = ZonedDateTime.parse(input, inputFormatter).toLocalDate()
                dateTime.format(outputFormatter)
            } catch (e: Exception) {
                input // Return original input if parsing fails
            }
        }
    }
}