package ani.dantotsu.profile.activity

import android.annotation.SuppressLint
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.ViewGroup
import android.widget.CheckBox
import android.widget.ImageButton
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.core.content.ContextCompat
import androidx.core.view.isVisible
import androidx.core.view.updateLayoutParams
import androidx.lifecycle.lifecycleScope
import androidx.recyclerview.widget.LinearLayoutManager
import ani.dantotsu.R
import ani.dantotsu.connections.anilist.Anilist
import ani.dantotsu.connections.anilist.api.Notification
import ani.dantotsu.connections.anilist.api.NotificationType
import ani.dantotsu.connections.anilist.api.NotificationType.Companion.fromFormattedString
import ani.dantotsu.currContext
import ani.dantotsu.databinding.ActivityFollowBinding
import ani.dantotsu.initActivity
import ani.dantotsu.media.MediaDetailsActivity
import ani.dantotsu.navBarHeight
import ani.dantotsu.notifications.comment.CommentStore
import ani.dantotsu.notifications.subscription.SubscriptionStore
import ani.dantotsu.profile.ProfileActivity
import ani.dantotsu.settings.saving.PrefManager
import ani.dantotsu.settings.saving.PrefName
import ani.dantotsu.statusBarHeight
import ani.dantotsu.themes.ThemeManager
import ani.dantotsu.util.Logger
import com.xwray.groupie.GroupieAdapter
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext

class NotificationActivity : AppCompatActivity() {
    private lateinit var binding: ActivityFollowBinding
    private lateinit var commentStore: List<CommentStore>
    private lateinit var subscriptionStore: List<SubscriptionStore>
    private var adapter: GroupieAdapter = GroupieAdapter()
    private var notificationList: List<Notification> = emptyList()
    val filters = ArrayList<String>()
    private var currentPage: Int = 1
    private var hasNextPage: Boolean = true

    @SuppressLint("ClickableViewAccessibility")
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        ThemeManager(this).applyTheme()
        initActivity(this)
        binding = ActivityFollowBinding.inflate(layoutInflater)
        setContentView(binding.root)
        binding.listTitle.text = getString(R.string.notifications)
        binding.listToolbar.updateLayoutParams<ViewGroup.MarginLayoutParams> {
            topMargin = statusBarHeight
        }
        binding.listFrameLayout.updateLayoutParams<ViewGroup.MarginLayoutParams> {
            bottomMargin = navBarHeight
        }
        binding.listRecyclerView.adapter = adapter
        binding.listRecyclerView.layoutManager =
            LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false)
        binding.followerGrid.visibility = ViewGroup.GONE
        binding.followerList.visibility = ViewGroup.GONE
        binding.listBack.setOnClickListener {
            onBackPressedDispatcher.onBackPressed()
        }
        binding.listProgressBar.visibility = ViewGroup.VISIBLE
        commentStore = PrefManager.getNullableVal<List<CommentStore>>(
            PrefName.CommentNotificationStore,
            null
        ) ?: listOf()
        subscriptionStore = PrefManager.getNullableVal<List<SubscriptionStore>>(
            PrefName.SubscriptionNotificationStore,
            null
        ) ?: listOf()

        binding.followFilterButton.setOnClickListener {
            val dialogView = LayoutInflater.from(currContext()).inflate(R.layout.custom_dialog_layout, null)
            val checkboxContainer = dialogView.findViewById<LinearLayout>(R.id.checkboxContainer)
            val tickAllButton = dialogView.findViewById<ImageButton>(R.id.toggleButton)
            val title = dialogView.findViewById<TextView>(R.id.scantitle)
            title.visibility = ViewGroup.GONE
            fun getToggleImageResource(container: ViewGroup): Int {
                var allChecked = true
                var allUnchecked = true

                for (i in 0 until container.childCount) {
                    val checkBox = container.getChildAt(i) as CheckBox
                    if (!checkBox.isChecked) {
                        allChecked = false
                    } else {
                        allUnchecked = false
                    }
                }
                return when {
                    allChecked -> R.drawable.untick_all_boxes
                    allUnchecked -> R.drawable.tick_all_boxes
                    else -> R.drawable.invert_all_boxes
                }
            }
            NotificationType.entries.forEach { notificationType ->
                val checkBox = CheckBox(currContext())
                checkBox.text = notificationType.toFormattedString()
                checkBox.isChecked = !filters.contains(notificationType.value.fromFormattedString())
                checkBox.setOnCheckedChangeListener { _, isChecked ->
                    if (isChecked) {
                        filters.remove(notificationType.value.fromFormattedString())
                    } else {
                        filters.add(notificationType.value.fromFormattedString())
                    }
                    tickAllButton.setImageResource(getToggleImageResource(checkboxContainer))
                }
                checkboxContainer.addView(checkBox)
            }
            tickAllButton.setImageResource(getToggleImageResource(checkboxContainer))
            tickAllButton.setOnClickListener {
                for (i in 0 until checkboxContainer.childCount) {
                    val checkBox = checkboxContainer.getChildAt(i) as CheckBox
                    checkBox.isChecked = !checkBox.isChecked
                }

                tickAllButton.setImageResource(getToggleImageResource(checkboxContainer))
            }
            val alertD = AlertDialog.Builder(this, R.style.MyPopup)
            alertD.setTitle("Filter")
            alertD.setView(dialogView)
            alertD.setPositiveButton("OK") { _, _ ->
                currentPage = 1
                hasNextPage = true
                adapter.clear()
                adapter.addAll(notificationList.filter { notification ->
                    !filters.contains(notification.notificationType)
                }.map {
                    NotificationItem(
                        it,
                        ::onNotificationClick
                    )
                })
                loadPage(-1) {
                    binding.followRefresh.visibility = ViewGroup.GONE
                }
            }
            alertD.setNegativeButton("Cancel") { _, _ -> }
            val dialog = alertD.show()
            dialog.window?.setDimAmount(0.8f)
        }

        val activityId = intent.getIntExtra("activityId", -1)
        lifecycleScope.launch {
            loadPage(activityId) {
                binding.listProgressBar.visibility = ViewGroup.GONE
            }
            withContext(Dispatchers.Main) {
                binding.listProgressBar.visibility = ViewGroup.GONE
                binding.listRecyclerView.setOnTouchListener { _, event ->
                    if (event?.action == MotionEvent.ACTION_UP) {
                        if (hasNextPage && !binding.listRecyclerView.canScrollVertically(1) && !binding.followRefresh.isVisible
                            && binding.listRecyclerView.adapter!!.itemCount != 0 &&
                            (binding.listRecyclerView.layoutManager as LinearLayoutManager).findLastVisibleItemPosition() == (binding.listRecyclerView.adapter!!.itemCount - 1)
                        ) {
                            binding.followRefresh.visibility = ViewGroup.VISIBLE
                            loadPage(-1) {
                                binding.followRefresh.visibility = ViewGroup.GONE
                            }
                        }
                    }
                    false
                }

                binding.followSwipeRefresh.setOnRefreshListener {
                    currentPage = 1
                    hasNextPage = true
                    adapter.clear()
                    notificationList = emptyList()
                    loadPage(-1) {
                        binding.followSwipeRefresh.isRefreshing = false
                    }
                }
            }
        }
    }

    private fun loadPage(activityId: Int, onFinish: () -> Unit = {}) {
        lifecycleScope.launch(Dispatchers.IO) {
            val resetNotification = activityId == -1
            val res = Anilist.query.getNotifications(
                Anilist.userid ?: PrefManager.getVal<String>(PrefName.AnilistUserId).toIntOrNull()
                ?: 0, currentPage, resetNotification = resetNotification
            )
            withContext(Dispatchers.Main) {
                val newNotifications: MutableList<Notification> = mutableListOf()
                res?.data?.page?.notifications?.let { notifications ->
                    Logger.log("Notifications: $notifications")
                    newNotifications += if (activityId != -1) {
                        notifications.filter { it.id == activityId }
                    } else {
                        notifications
                    }.toMutableList()
                }
                if (activityId == -1) {
                    val furthestTime = newNotifications.minOfOrNull { it.createdAt } ?: 0
                    commentStore.forEach {
                        if ((it.time > furthestTime * 1000L || !hasNextPage) && notificationList.none { notification ->
                                notification.commentId == it.commentId && notification.createdAt == (it.time / 1000L).toInt()
                            }) {
                            val notification = Notification(
                                it.type.toString(),
                                System.currentTimeMillis().toInt(),
                                commentId = it.commentId,
                                notificationType = it.type.toString(),
                                mediaId = it.mediaId,
                                context = it.title + "\n" + it.content,
                                createdAt = (it.time / 1000L).toInt(),
                            )
                            newNotifications += notification
                        }
                    }
                    subscriptionStore.forEach {
                        if ((it.time > furthestTime * 1000L || !hasNextPage) && notificationList.none { notification ->
                                notification.mediaId == it.mediaId && notification.createdAt == (it.time / 1000L).toInt()
                            }) {
                            val notification = Notification(
                                it.type,
                                System.currentTimeMillis().toInt(),
                                commentId = it.mediaId,
                                mediaId = it.mediaId,
                                notificationType = it.type,
                                context = it.title + ": " + it.content,
                                createdAt = (it.time / 1000L).toInt(),
                                image = it.image,
                                banner = it.banner ?: it.image
                            )
                            newNotifications += notification
                        }
                    }
                    newNotifications.sortByDescending { it.createdAt }
                }

                notificationList += newNotifications
                adapter.addAll(newNotifications.filter { notification ->
                    !filters.contains(notification.notificationType)
                }.map {
                    NotificationItem(
                        it,
                        ::onNotificationClick
                    )
                })
                currentPage = res?.data?.page?.pageInfo?.currentPage?.plus(1) ?: 1
                hasNextPage = res?.data?.page?.pageInfo?.hasNextPage ?: false
                binding.followSwipeRefresh.isRefreshing = false
                onFinish()
            }
        }
    }

    private fun onNotificationClick(id: Int, optional: Int?, type: NotificationClickType) {
        when (type) {
            NotificationClickType.USER -> {
                ContextCompat.startActivity(
                    this, Intent(this, ProfileActivity::class.java)
                        .putExtra("userId", id), null
                )
            }

            NotificationClickType.MEDIA -> {
                ContextCompat.startActivity(
                    this, Intent(this, MediaDetailsActivity::class.java)
                        .putExtra("mediaId", id), null
                )
            }

            NotificationClickType.ACTIVITY -> {
                ContextCompat.startActivity(
                    this, Intent(this, FeedActivity::class.java)
                        .putExtra("activityId", id), null
                )
            }

            NotificationClickType.COMMENT -> {
                ContextCompat.startActivity(
                    this, Intent(this, MediaDetailsActivity::class.java)
                        .putExtra("FRAGMENT_TO_LOAD", "COMMENTS")
                        .putExtra("mediaId", id)
                        .putExtra("commentId", optional ?: -1),
                    null
                )

            }

            NotificationClickType.UNDEFINED -> {
                // Do nothing
            }
        }
    }

    companion object {
        enum class NotificationClickType {
            USER, MEDIA, ACTIVITY, COMMENT, UNDEFINED
        }
    }
}