package com.ejada.hmg.utils

import android.app.NotificationChannel
import android.app.NotificationManager
import android.app.PendingIntent
import android.app.job.JobInfo
import android.app.job.JobScheduler
import android.content.ComponentName
import android.content.Context
import android.content.Intent
import android.os.Build
import android.widget.Toast
import androidx.annotation.Nullable
import androidx.core.app.NotificationCompat
import androidx.core.app.TaskStackBuilder
import com.ejada.hmg.BuildConfig
import com.ejada.hmg.MainActivity
import com.ejada.hmg.R
import com.ejada.hmg.geofence.GeoZoneModel
import com.github.kittinunf.fuel.core.extensions.jsonBody
import com.github.kittinunf.fuel.httpPost
import com.google.gson.Gson
import com.google.gson.reflect.TypeToken
import io.flutter.plugin.common.MethodChannel
//import org.jetbrains.anko.doAsyncResult
import org.json.JSONArray
import org.json.JSONException
import org.json.JSONObject
import java.text.SimpleDateFormat
import java.util.*
import kotlin.concurrent.timerTask


class HMGUtils {

    companion object{
        private lateinit var platformChannel: MethodChannel
        fun getPlatformChannel():MethodChannel{
            return platformChannel
        }
        fun setPlatformChannel(channel: MethodChannel){
            platformChannel = channel
        }

        fun timer(delay: Long, repeat: Boolean, tick: (Timer) -> Unit) : Timer{
            val timer = Timer()
            if(repeat)
                timer.schedule(timerTask {
                    tick(timer)
                }, delay, delay)
            else
                timer.schedule(timerTask {
                    tick(timer)
                }, delay)

            return timer
        }

        fun popMessage(context: MainActivity, message: String){
            context.runOnUiThread {
                Toast.makeText(context, message, Toast.LENGTH_LONG).show()
            }
        }

        fun popFlutterText(context: MainActivity, key: String){
            context.runOnUiThread {
                FlutterText.with(key){
                    Toast.makeText(context, it, Toast.LENGTH_LONG).show()
                }
            }
        }

        fun getLanguageCode(context: Context) : Int {
            val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
            val lang = pref.getString(PREF_KEY_LANGUAGE, "ar")
            return if (lang == "ar") 2 else 1
        }

        fun defaultHTTPParams(context: Context) : Map<String, Any?>{
            return mapOf(
                    "ZipCode" to "966",
                    "VersionID" to 5.8,
                    "Channel" to 3,
                    "LanguageID" to getLanguageCode(context),
                    "IPAdress" to "10.20.10.20",
                    "generalid" to "Cs2020@2016$2958",
                    "PatientOutSA" to 0,
                    "SessionID" to null,
                    "isDentalAllowedBackend" to false,
                    "DeviceTypeID" to 2)
        }


        fun <T>scheduleJob(context: Context, pendingIntentClassType:Class<T>, jobId:Int, intervalDuration:String, deadlineMillis:Long = (30 * 1000)) { //  default deadline: 30 Seconds
            if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.M) {
                val jobScheduler: JobScheduler = context.getSystemService(JobScheduler::class.java)

                val serviceComponent = ComponentName(context, pendingIntentClassType)
                val builder = JobInfo.Builder(jobId, serviceComponent)
                builder.setPersisted(true)
                builder.setBackoffCriteria(30000, JobInfo.BACKOFF_POLICY_LINEAR)

                val intervalMillis = timeToMillis(intervalDuration,"HH:mm:ss")
                builder.setMinimumLatency(intervalMillis) // wait at least
                builder.setOverrideDeadline((intervalMillis + deadlineMillis)) // maximum delay
                if (jobScheduler.schedule(builder.build()) == JobScheduler.RESULT_SUCCESS){
                    Logs.save(context,"ScheduleJob", "${pendingIntentClassType.simpleName}: Job scheduled to trigger after duration $intervalDuration >> HH:mm:ss  --('MinimumLatency:$intervalMillis Deadline:${(intervalMillis + deadlineMillis)}')--",Logs.STATUS.SUCCESS)
                }else{
                    Logs.save(context,"ScheduleJob", "${pendingIntentClassType.simpleName}: Failed to scheduled Job",Logs.STATUS.ERROR)
                }

            } else {
                Logs.save(context,"ScheduleJob", "${pendingIntentClassType.simpleName}: Failed to scheduled Job on VERSION.SDK_INT < ${android.os.Build.VERSION_CODES.M}",Logs.STATUS.ERROR)
            }
        }

    }

}


private const val NOTIFICATION_CHANNEL_ID = BuildConfig.APPLICATION_ID + ".channel"


fun timeToMillis(time:String, format:String):Long{
    val sdf = SimpleDateFormat(format, Locale.US)
    val millis = sdf.parse(time).time + TimeZone.getDefault().rawOffset
    return millis
}

fun sendNotification(context: Context, title: String, @Nullable subtitle: String?, message: String?) {
    val notificationManager = context.getSystemService(Context.NOTIFICATION_SERVICE) as NotificationManager

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
            && notificationManager.getNotificationChannel(NOTIFICATION_CHANNEL_ID) == null) {
        val name = context.getString(R.string.app_name)
        val channel = NotificationChannel(NOTIFICATION_CHANNEL_ID,
                name,
                NotificationManager.IMPORTANCE_DEFAULT)

        notificationManager.createNotificationChannel(channel)
    }

    val intent = Intent(context, MainActivity::class.java)

    val stackBuilder = TaskStackBuilder.create(context)
            .addParentStack(MainActivity::class.java)
            .addNextIntent(intent)
    val notificationPendingIntent = stackBuilder.getPendingIntent(getUniqueId(), PendingIntent.FLAG_UPDATE_CURRENT)

    val notification = NotificationCompat.Builder(context, NOTIFICATION_CHANNEL_ID)
            .setSmallIcon(R.mipmap.ic_launcher_local)
            .setContentIntent(notificationPendingIntent)
            .setAutoCancel(true)
            .setContentTitle(title)

    subtitle.let { notification.setContentText(it) }
    message.let { notification.setSubText(it) }

    notificationManager.notify(getUniqueId(), notification.build())
}

//-------------------------
// Open Helper Methods
//-------------------------
fun getUniqueId() = ((System.currentTimeMillis() % 10000).toInt())

object DateUtils {
    @JvmStatic
    fun dateTimeNow() : String {
        val format = SimpleDateFormat("dd-MMM-yyy hh:mm:ss")
        return format.format(Date())
    }
}

fun isJSONValid(jsonString: String?): Boolean {
    try { JSONObject(jsonString) } catch (ex: JSONException) {
        try {  JSONArray(jsonString) } catch (ex1: JSONException) {
            return false
        }
    }
    return true
}

fun saveLog(context: Context, tag: String, message: String){
    val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
    var logs = pref.getString("LOGS", "")
    logs += "$tag ->  $message \n"
    pref.edit().putString("LOGS", logs).apply();
}

fun getLogs(context: Context) : String?{
    val pref = context.getSharedPreferences(PREFS_STORAGE, Context.MODE_PRIVATE)
    return pref.getString("LOGS", "")
}

class HTTPResponse<T>(data: T){
    final var data:T = data
}

fun <T>httpPost(url: String, body: Map<String, Any?>, onSuccess: (response: HTTPResponse<T>) -> Unit, onError: (error: Exception) -> Unit){
    val gson = Gson()
    val type =  object : TypeToken<T>() {}.type
    val jsonBody = gson.toJson(body)
    url.httpPost()
            .jsonBody(jsonBody, Charsets.UTF_8)
            .timeout(10000)
            .header("Content-Type", "application/json")
            .header("Allow", "*/*")
            .response { request, response, result ->
                result.fold({ data ->
                    val dataString = String(data)
                    if (isJSONValid(dataString)) {
                        val responseData = gson.fromJson<T>(dataString, type)
                        onSuccess(HTTPResponse(responseData))
                    } else {
                        onError(Exception("Invalid response from server (Not a valid JSON)"))
                    }
                }, {
                    onError(it)
                })

            }
}