package kr.co.vividnext.sodalive.message.voice

import android.annotation.SuppressLint
import android.graphics.Rect
import android.media.MediaPlayer
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.View
import android.widget.SeekBar
import android.widget.TextView
import android.widget.Toast
import androidx.core.content.ContextCompat
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import com.orhanobut.logger.Logger
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseFragment
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.databinding.FragmentVoiceMessageBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.message.MessageBox
import org.koin.android.ext.android.inject
import java.util.Timer
import java.util.TimerTask
import java.util.concurrent.TimeUnit

class VoiceMessageFragment : BaseFragment<FragmentVoiceMessageBinding>(
    FragmentVoiceMessageBinding::inflate
) {
    private val viewModel: VoiceMessageViewModel by inject()

    private lateinit var adapter: VoiceMessageAdapter

    private lateinit var loadingDialog: LoadingDialog

    private var mediaPlayer: MediaPlayer? = null

    private val handler = Handler(Looper.getMainLooper())
    private var timerTask: TimerTask? = null
    private var timer: Timer? = null

    override fun onDestroy() {
        if (mediaPlayer != null) {
            mediaPlayer!!.release()
            mediaPlayer = null
        }

        super.onDestroy()
    }

    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)

        setupView()
        bindData()

        viewModel.getMessages()
    }

    private fun setupView() {
        loadingDialog = LoadingDialog(requireActivity(), layoutInflater)

        binding.tvSent.setOnClickListener {
            adapter.setMessageBox(MessageBox.SENT)
            viewModel.selectMessageBox(
                MessageBox.SENT
            )
        }

        binding.tvReceive.setOnClickListener {
            adapter.setMessageBox(MessageBox.RECEIVE)
            viewModel.selectMessageBox(
                MessageBox.RECEIVE
            )
        }

        binding.tvKeep.setOnClickListener {
            adapter.setMessageBox(MessageBox.KEEP)
            viewModel.selectMessageBox(
                MessageBox.KEEP
            )
        }

        binding.ivWrite.setOnClickListener {
            stopVoiceMessage()
            val voiceWriteFragment = VoiceMessageWriteFragment(
                onSendSuccess = {
                    viewModel.page = 1
                    viewModel.getMessages()
                }
            )
            voiceWriteFragment.show(childFragmentManager, voiceWriteFragment.tag)
        }

        val recyclerView = binding.rvMessage
        adapter = VoiceMessageAdapter(
            onPlay = { playVoiceMessage(it.voiceMessageUrl) },
            onStop = { stopVoiceMessage() },
            onStartSeekbar = { seekbar, textView ->
                startSeekbar(seekbar, textView)
            },
            onItemDelete = {
                viewModel.deleteMessage(it) {
                    Toast.makeText(
                        requireContext(),
                        "메시지가 삭제되었습니다.",
                        Toast.LENGTH_LONG
                    ).show()

                    viewModel.page = 1
                    viewModel.getMessages()
                }
            },
            onItemKeep = { messageId, isKept ->
                if (isKept) {
                    Toast.makeText(
                        requireContext(),
                        "이미 보관된 메시지 입니다.",
                        Toast.LENGTH_LONG
                    ).show()
                    return@VoiceMessageAdapter
                }

                viewModel.keepVoiceMessage(messageId)
            },
            onItemReply = { senderId, senderNickname, senderProfileUrl ->
                stopVoiceMessage()
                val voiceWriteFragment = VoiceMessageWriteFragment(
                    onSendSuccess = {
                        viewModel.page = 1
                        viewModel.getMessages()
                    },
                    senderId = senderId,
                    senderNickname = senderNickname,
                    senderProfileUrl = senderProfileUrl
                )
                voiceWriteFragment.show(childFragmentManager, voiceWriteFragment.tag)
            }
        )

        recyclerView.layoutManager = LinearLayoutManager(
            requireContext(),
            LinearLayoutManager.VERTICAL,
            false
        )

        recyclerView.addItemDecoration(object : RecyclerView.ItemDecoration() {
            override fun getItemOffsets(
                outRect: Rect,
                view: View,
                parent: RecyclerView,
                state: RecyclerView.State
            ) {
                super.getItemOffsets(outRect, view, parent, state)

                outRect.left = 13.3f.dpToPx().toInt()
                outRect.right = 13.3f.dpToPx().toInt()
                outRect.top = 13.3f.dpToPx().toInt()
                outRect.bottom = 13.3f.dpToPx().toInt()
            }
        })

        recyclerView.adapter = adapter

        recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() {
            override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
                super.onScrolled(recyclerView, dx, dy)

                val lastVisibleItemPosition = (recyclerView.layoutManager as LinearLayoutManager?)!!
                    .findLastCompletelyVisibleItemPosition()
                val itemTotalCount = recyclerView.adapter!!.itemCount - 1

                // 스크롤이 끝에 도달했는지 확인
                if (!recyclerView.canScrollVertically(1) &&
                    lastVisibleItemPosition == itemTotalCount
                ) {
                    viewModel.getMessages(viewModel.messageBoxLiveData.value!!)
                }
            }
        })
    }

    private fun startSeekbar(seekbar: SeekBar, textView: TextView) {
        if (timer != null) {
            timer!!.cancel()
            timerTask = null
            timer = null
        }

        if (mediaPlayer != null) {
            val duration = mediaPlayer?.duration!!
            seekbar.max = duration
            var seconds = TimeUnit.MILLISECONDS.toSeconds(duration.toLong())
            val minutes = seconds / 60
            seconds %= 60
            textView.text = String.format("%02d:%02d", minutes, seconds)

            timerTask = object : TimerTask() {
                override fun run() {
                    handler.post {
                        seekbar.progress = mediaPlayer?.currentPosition ?: 0
                    }
                }
            }

            timer = Timer()
            timer!!.scheduleAtFixedRate(timerTask, 0, 100)
        }
    }

    private fun playVoiceMessage(voiceMessageUrl: String): Int {
        if (mediaPlayer == null) {
            mediaPlayer = MediaPlayer()
            mediaPlayer!!.reset()

            mediaPlayer!!.setOnCompletionListener {
                stopVoiceMessage()
            }

            mediaPlayer!!.setOnPreparedListener {
                it.start()
            }

            try {
                mediaPlayer!!.setDataSource(voiceMessageUrl)
                mediaPlayer!!.prepare()
            } catch (e: Exception) {
                Toast.makeText(requireActivity(), R.string.retry, Toast.LENGTH_LONG).show()
                return 0
            }

            return mediaPlayer!!.duration
        }

        return 0
    }

    private fun stopVoiceMessage() {
        if (timer != null) {
            timer!!.cancel()
            timerTask = null
            timer = null
        }

        if (mediaPlayer != null) {
            adapter.voicePlayComplete()
            mediaPlayer!!.release()
            mediaPlayer = null
        }
    }

    @SuppressLint("NotifyDataSetChanged")
    private fun bindData() {
        viewModel.toastLiveData.observe(viewLifecycleOwner) {
            it?.let { Toast.makeText(requireActivity(), it, Toast.LENGTH_LONG).show() }
        }

        viewModel.isLoading.observe(viewLifecycleOwner) {
            if (it) {
                loadingDialog.show(screenWidth, "음성 메시지를 불러오고 있습니다.")
            } else {
                loadingDialog.dismiss()
            }
        }

        viewModel.getMessagesLiveData.observe(viewLifecycleOwner) {
            if (viewModel.page - 1 == 1) {
                adapter.items.clear()
            }

            if (adapter.items.size == 0 && it.isEmpty()) {
                binding.rvMessage.visibility = View.GONE
                binding.llNoItems.visibility = View.VISIBLE
            } else {
                binding.rvMessage.visibility = View.VISIBLE
                binding.llNoItems.visibility = View.GONE
                adapter.items.addAll(it)
                adapter.notifyDataSetChanged()
            }
        }

        viewModel.messageBoxLiveData.observe(viewLifecycleOwner) {
            binding.tvSent.setBackgroundResource(R.drawable.bg_round_corner_16_7_transparent_777777)
            binding.tvSent.setTextColor(
                ContextCompat.getColor(
                    requireContext(),
                    R.color.color_777777
                )
            )

            binding.tvReceive.setBackgroundResource(
                R.drawable.bg_round_corner_16_7_transparent_777777
            )
            binding.tvReceive.setTextColor(
                ContextCompat.getColor(
                    requireContext(),
                    R.color.color_777777
                )
            )

            binding.tvKeep.setBackgroundResource(
                R.drawable.bg_round_corner_16_7_transparent_777777
            )
            binding.tvKeep.setTextColor(
                ContextCompat.getColor(
                    requireContext(),
                    R.color.color_777777
                )
            )

            when (it) {
                MessageBox.SENT -> {
                    binding.tvSent.setBackgroundResource(
                        R.drawable.bg_round_corner_16_7_transparent_3bb9f1
                    )
                    binding.tvSent.setTextColor(
                        ContextCompat.getColor(
                            requireContext(),
                            R.color.color_3bb9f1
                        )
                    )
                }

                MessageBox.RECEIVE -> {
                    binding.tvReceive.setBackgroundResource(
                        R.drawable.bg_round_corner_16_7_transparent_3bb9f1
                    )
                    binding.tvReceive.setTextColor(
                        ContextCompat.getColor(
                            requireContext(),
                            R.color.color_3bb9f1
                        )
                    )
                }

                MessageBox.KEEP -> {
                    binding.tvKeep.setBackgroundResource(
                        R.drawable.bg_round_corner_16_7_transparent_3bb9f1
                    )
                    binding.tvKeep.setTextColor(
                        ContextCompat.getColor(
                            requireContext(),
                            R.color.color_3bb9f1
                        )
                    )
                }

                else -> {
                }
            }
        }
    }
}
