package kr.co.vividnext.sodalive.live.reservation.all

import android.annotation.SuppressLint
import android.content.Intent
import android.graphics.Rect
import android.os.Bundle
import android.view.View
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.michalsvec.singlerowcalendar.calendar.CalendarChangesObserver
import com.michalsvec.singlerowcalendar.calendar.CalendarViewManager
import com.michalsvec.singlerowcalendar.calendar.SingleRowCalendarAdapter
import com.michalsvec.singlerowcalendar.selection.CalendarSelectionManager
import com.michalsvec.singlerowcalendar.utils.DateUtils
import kr.co.vividnext.sodalive.R
import kr.co.vividnext.sodalive.base.BaseActivity
import kr.co.vividnext.sodalive.common.Constants
import kr.co.vividnext.sodalive.common.LoadingDialog
import kr.co.vividnext.sodalive.common.SharedPreferenceManager
import kr.co.vividnext.sodalive.databinding.ActivityLiveReservationAllBinding
import kr.co.vividnext.sodalive.extensions.dpToPx
import kr.co.vividnext.sodalive.extensions.moneyFormat
import kr.co.vividnext.sodalive.live.LiveViewModel
import kr.co.vividnext.sodalive.live.reservation.LiveReservationAdapter
import kr.co.vividnext.sodalive.live.reservation.complete.LiveReservationCompleteActivity
import kr.co.vividnext.sodalive.live.room.LiveRoomActivity
import kr.co.vividnext.sodalive.live.room.detail.GetRoomDetailResponse
import kr.co.vividnext.sodalive.live.room.detail.LiveRoomDetailFragment
import kr.co.vividnext.sodalive.live.room.dialog.LiveCancelDialog
import kr.co.vividnext.sodalive.live.room.dialog.LivePaymentDialog
import kr.co.vividnext.sodalive.live.room.dialog.LiveRoomPasswordDialog
import kr.co.vividnext.sodalive.live.room.update.LiveRoomEditActivity
import org.koin.android.ext.android.inject
import java.text.SimpleDateFormat
import java.util.Calendar
import java.util.Date
import java.util.Locale

class LiveReservationAllActivity : BaseActivity<ActivityLiveReservationAllBinding>(
    ActivityLiveReservationAllBinding::inflate
) {
    private val viewModel: LiveViewModel by inject()

    private lateinit var loadingDialog: LoadingDialog
    private lateinit var adapter: LiveReservationAdapter
    private lateinit var selectedDateString: String

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setupCalendar()
    }

    private fun setupCalendar() {
        val myCalendarViewManager = object : CalendarViewManager {
            override fun setCalendarViewResourceId(
                position: Int,
                date: Date,
                isSelected: Boolean
            ): Int {
                return if (isSelected)
                    R.layout.item_calendar_selected
                else
                    R.layout.item_calendar
            }

            override fun bindDataToCalendarView(
                holder: SingleRowCalendarAdapter.CalendarViewHolder,
                date: Date,
                position: Int,
                isSelected: Boolean
            ) {
                holder.itemView.findViewById<TextView>(
                    R.id.tv_date_calendar_item
                ).text = DateUtils.getDayNumber(date)

                val tvDayCalendarItem = holder.itemView.findViewById<TextView>(
                    R.id.tv_day_calendar_item
                )
                tvDayCalendarItem.text = DateUtils.getDay3LettersName(date)

                val cal = Calendar.getInstance()
                cal.time = date
                when (cal[Calendar.DAY_OF_WEEK]) {
                    Calendar.SATURDAY -> tvDayCalendarItem.setTextColor(
                        ContextCompat.getColor(
                            applicationContext,
                            R.color.color_2f90b7
                        )
                    )

                    Calendar.SUNDAY -> tvDayCalendarItem.setTextColor(
                        ContextCompat.getColor(
                            applicationContext,
                            R.color.color_a94400
                        )
                    )

                    else -> tvDayCalendarItem.setTextColor(
                        ContextCompat.getColor(
                            applicationContext,
                            R.color.white
                        )
                    )
                }
            }
        }

        // using calendar changes observer we can track changes in calendar
        val myCalendarChangesObserver = object :
            CalendarChangesObserver {
            // you can override more methods, in this example we need only this one
            override fun whenSelectionChanged(isSelected: Boolean, position: Int, date: Date) {
                if (isSelected) {
                    val sdf = SimpleDateFormat("yyyy-MM-dd", Locale.getDefault())
                    selectedDateString = sdf.format(date.time)

                    adapter.clear()
                    viewModel.page = 1
                    viewModel.isLast = false
                    viewModel.getLiveReservation(selectedDateString)
                }
                super.whenSelectionChanged(isSelected, position, date)
            }
        }

        // selection manager is responsible for managing selection
        val mySelectionManager = object : CalendarSelectionManager {
            override fun canBeItemSelected(position: Int, date: Date): Boolean {
                return true
            }
        }

        binding.calendarView.apply {
            calendarViewManager = myCalendarViewManager
            calendarChangesObserver = myCalendarChangesObserver
            calendarSelectionManager = mySelectionManager
            setDates(getDates(mutableListOf()))
            init()
            select(0)
        }
    }

    private fun getDates(list: MutableList<Date>): List<Date> {
        // load dates of whole month
        val calendar = Calendar.getInstance()
        val currentMonth = calendar[Calendar.MONTH]
        calendar.set(Calendar.MONTH, currentMonth)
        calendar.set(Calendar.DAY_OF_MONTH, calendar[Calendar.DAY_OF_MONTH])
        list.add(calendar.time)
        for (index in 1..6) {
            calendar.add(Calendar.DATE, +1)
            list.add(calendar.time)
        }
        calendar.add(Calendar.DATE, -1)
        return list
    }

    @SuppressLint("NotifyDataSetChanged")
    override fun setupView() {
        binding.toolbar.tvBack.text = "라이브, 예약 캘린더"
        binding.toolbar.tvBack.setOnClickListener { finish() }

        loadingDialog = LoadingDialog(this, layoutInflater)

        val recyclerView = binding.rvCounselor

        viewModel.toastLiveData.observe(this) {
            it?.let { Toast.makeText(this, it, Toast.LENGTH_LONG).show() }
        }

        viewModel.isLoading.observe(this) {
            if (it) {
                loadingDialog.show(screenWidth, "")
            } else {
                loadingDialog.dismiss()
            }
        }

        viewModel.liveReservationLiveData.observe(this) {
            if (it.isEmpty()) {
                if (adapter.items.isEmpty()) {
                    binding.swipeRefreshLayout.visibility = View.GONE
                    binding.llNoItems.visibility = View.VISIBLE
                }
            } else {
                binding.swipeRefreshLayout.visibility = View.VISIBLE
                binding.llNoItems.visibility = View.GONE
                adapter.items.addAll(it)
                adapter.notifyDataSetChanged()
            }
        }

        adapter = LiveReservationAdapter {
            val detailFragment = LiveRoomDetailFragment(
                it.roomId,
                onClickParticipant = {},
                onClickReservation = { onClickReservation(it.roomId) },
                onClickModify = { roomDetailResponse -> onClickModify(roomDetailResponse) },
                onClickStart = { onClickStart(it.roomId) },
                onClickCancel = { onClickCancel(it.roomId) }
            )

            if (detailFragment.isAdded) return@LiveReservationAdapter

            detailFragment.show(
                supportFragmentManager,
                detailFragment.tag
            )
        }

        recyclerView.layoutManager = LinearLayoutManager(
            applicationContext,
            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)

                when (parent.getChildAdapterPosition(view)) {
                    0 -> {
                        outRect.top = 0.dpToPx().toInt()
                        outRect.bottom = 6.7f.dpToPx().toInt()
                    }

                    adapter.itemCount - 1 -> {
                        outRect.top = 6.7f.dpToPx().toInt()
                        outRect.bottom = 0.dpToPx().toInt()
                    }

                    else -> {
                        outRect.top = 6.7f.dpToPx().toInt()
                        outRect.bottom = 6.7f.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 lastVisiblePosition = (recyclerView.layoutManager as LinearLayoutManager)
                    .findLastVisibleItemPosition()
                val itemTotalCount = adapter.itemCount - 1

                if (lastVisiblePosition == itemTotalCount) {
                    viewModel.getLiveReservation(selectedDateString)
                }
            }
        })

        binding.swipeRefreshLayout.setOnRefreshListener { refresh() }
    }

    private fun refresh() {
        adapter.clear()
        viewModel.page = 1
        viewModel.isLast = false
        viewModel.getLiveReservation(selectedDateString)

        binding.swipeRefreshLayout.isRefreshing = false
    }

    private fun onClickReservation(roomId: Long) {
        viewModel.getRoomDetail(roomId) {
            if (it.manager.id == SharedPreferenceManager.userId) {
                showToast("내가 만든 라이브는 예약할 수 없습니다.")
            } else {
                if (it.isPrivateRoom) {
                    LiveRoomPasswordDialog(
                        activity = this,
                        layoutInflater = layoutInflater,
                        can = if (it.isPaid) 0 else it.price,
                        confirmButtonClick = { password ->
                            processLiveReservation(roomId, password)
                        }
                    ).show(screenWidth)
                } else {
                    if (it.price == 0 || it.isPaid) {
                        processLiveReservation(roomId)
                    } else {
                        LivePaymentDialog(
                            activity = this,
                            layoutInflater = layoutInflater,
                            title = "${it.price.moneyFormat()} 캔으로 예약",
                            desc = "'${it.title}' 라이브에 참여하기 위해 결제합니다.",
                            confirmButtonTitle = "예약하기",
                            confirmButtonClick = { processLiveReservation(roomId) },
                            cancelButtonTitle = "취소",
                            cancelButtonClick = {}
                        ).show(screenWidth)
                    }
                }
            }
        }
    }

    private fun processLiveReservation(roomId: Long, password: String? = null) {
        viewModel.reservationRoom(roomId, password) {
            refresh()
            val intent = Intent(
                applicationContext,
                LiveReservationCompleteActivity::class.java
            )
            intent.putExtra(Constants.EXTRA_LIVE_RESERVATION_RESPONSE, it)
            startActivity(intent)
        }
    }

    private fun onClickStart(roomId: Long) {
        val onEnterRoomSuccess = {
            viewModel.getSummary()
            runOnUiThread {
                val intent = Intent(applicationContext, LiveRoomActivity::class.java)
                intent.putExtra(Constants.EXTRA_ROOM_ID, roomId)
                startActivity(intent)
            }
        }

        viewModel.startLive(roomId, onEnterRoomSuccess)
    }

    private fun onClickCancel(roomId: Long) {
        LiveCancelDialog(
            activity = this,
            layoutInflater = layoutInflater,
            title = "예약취소",
            hint = "취소사유를 입력하세요.",
            confirmButtonTitle = "예약취소",
            confirmButtonClick = {
                viewModel.cancelLive(roomId, it) {
                    Toast.makeText(
                        applicationContext,
                        "예약이 취소되었습니다.",
                        Toast.LENGTH_LONG
                    ).show()
                    adapter.clear()
                    refresh()
                }
            },
            cancelButtonTitle = "닫기",
            cancelButtonClick = {}
        ).show(screenWidth)
    }

    private fun onClickModify(roomDetail: GetRoomDetailResponse) {
        startActivity(
            Intent(applicationContext, LiveRoomEditActivity::class.java).apply {
                putExtra(Constants.EXTRA_ROOM_DETAIL, roomDetail)
            }
        )
    }
}
