package partisan.weforge.xyz.pulse

import android.Manifest
import android.content.Context
import android.content.Intent
import android.graphics.Color
import android.graphics.PixelFormat
import android.media.AudioManager
import android.net.Uri
import android.view.Gravity
import android.view.LayoutInflater
import android.view.WindowManager
import android.view.ContextThemeWrapper
import android.widget.TextView
import android.animation.ObjectAnimator
import android.widget.ProgressBar
import androidx.annotation.RequiresPermission
import androidx.core.content.res.use
import com.google.android.material.card.MaterialCardView
import java.lang.ref.WeakReference
import java.util.*
import kotlin.concurrent.timerTask
import android.util.Log
import android.content.res.ColorStateList
import com.google.android.material.color.DynamicColors
import com.google.android.material.color.MaterialColors

class PopupWindow(
    ctx: Context,
    private val service: WeakReference<CallRedirectionService>?,
) {
    private val themedCtx = DynamicColors.wrapContextIfAvailable(
        ContextThemeWrapper(ctx, R.style.Theme_Pulse)
    )
    private val prefs = Preferences(themedCtx)
    private val windowManager = themedCtx.getSystemService(WindowManager::class.java)
    private val audioManager = themedCtx.getSystemService(AudioManager::class.java)
    private val inflater = LayoutInflater.from(themedCtx)
    private val view = inflater.inflate(R.layout.popup, null)
    private val layoutParams = WindowManager.LayoutParams().apply {
        format = PixelFormat.TRANSLUCENT
        flags = WindowManager.LayoutParams.FLAG_NOT_FOCUSABLE
        type = WindowManager.LayoutParams.TYPE_APPLICATION_OVERLAY
        gravity = Gravity.BOTTOM
        width = WindowManager.LayoutParams.WRAP_CONTENT
        height = WindowManager.LayoutParams.WRAP_CONTENT
        y = prefs.popupPosition
    }
    private var timer: Timer? = null

    init {
        view.setOnClickListener {
            cancel()
            service?.get()?.placeCallUnmodified()
        }

        // This is utterly stupid, but it works
        applyResolvedColors(view)
    }

    fun preview() {
        remove()
        layoutParams.y = prefs.popupPosition
        val destinations = listOf(
            R.string.destination_signal,
            R.string.destination_telegram,
            R.string.destination_threema,
        )
        setDescription(destinations.random())
        add()
    }

    fun show(uri: Uri, destinationId: Int) {
        val service = service?.get() ?: return
        if (!remove()) {
            service.placeCallUnmodified()
            return
        }
        timer?.cancel()
        timer = Timer()
        timer?.schedule(timerTask {
            if (!remove()) {
                service.placeCallUnmodified()
                return@timerTask
            }
            if (audioManager?.mode != AudioManager.MODE_IN_CALL) {
                service.placeCallUnmodified()
                return@timerTask
            }
            try {
                call(uri)
            } catch (exc: SecurityException) {
                service.placeCallUnmodified()
                return@timerTask
            }
            service.cancelCall()
        }, prefs.redirectionDelay)
        setDescription(destinationId)
        startProgressAnimation(prefs.redirectionDelay)
        if (!add()) {
            timer?.cancel()
            service.placeCallUnmodified()
        }
    }

    private fun setDescription(id: Int) {
        view.findViewById<TextView>(R.id.description).text = themedCtx.getString(
            R.string.popup,
            themedCtx.getString(id),
        )
    }

    private fun startProgressAnimation(duration: Long) {
        val bar = view.findViewById<ProgressBar>(R.id.progress)
        bar.max = 100
        bar.progress = 0
        val animator = ObjectAnimator.ofInt(bar, "progress", 100)
        animator.duration = duration
        animator.start()
    }

    @RequiresPermission(Manifest.permission.CALL_PHONE)
    fun call(data: Uri) {
        Intent(Intent.ACTION_VIEW).apply {
            this.data = data
            flags = Intent.FLAG_ACTIVITY_NEW_TASK
            themedCtx.startActivity(this)
        }
    }

    private fun add(): Boolean {
        try {
            windowManager?.addView(view, layoutParams)
        } catch (exc: WindowManager.BadTokenException) {
            return false
        }
        return true
    }

    private fun remove(): Boolean {
        try {
            windowManager?.removeView(view)
        } catch (_: IllegalArgumentException) {
        } catch (_: WindowManager.BadTokenException) {
            return false
        }
        return true
    }

    fun cancel() {
        timer?.cancel()
        remove()
    }        

    private fun applyResolvedColors(view: android.view.View) {
        val attrSurface = com.google.android.material.R.attr.colorSurface
        val attrOnSurface = com.google.android.material.R.attr.colorOnSurface
        val attrPrimary = com.google.android.material.R.attr.colorPrimaryVariant

        try {
            themedCtx.obtainStyledAttributes(intArrayOf(attrSurface, attrOnSurface, attrPrimary)).use { ta ->
                val surface = ta.getColor(0, Color.LTGRAY)
                val onSurface = ta.getColor(1, Color.DKGRAY)
                val primary = ta.getColor(2, Color.DKGRAY)

                (view as? MaterialCardView)?.setCardBackgroundColor(surface)
                view.findViewById<TextView>(R.id.description)?.setTextColor(onSurface)

                view.findViewById<ProgressBar>(R.id.progress)?.let { bar ->
                    bar.progressTintList = ColorStateList.valueOf(primary)
                    bar.progressBackgroundTintList = ColorStateList.valueOf(
                        primary and 0x00FFFFFF or (0x40 shl 24)
                    )
                }

                view.invalidate()
            }
        } catch (e: Exception) {
            Log.e("PopupTheme", "Color resolution error: ${e.message}", e)
        }
    }
}
