package cz.muni.sutralog.ui.list

import android.app.AlertDialog
import android.app.DatePickerDialog
import android.app.Dialog
import android.content.DialogInterface
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.os.Bundle
import android.text.Editable
import android.text.TextWatcher
import android.view.*
import android.widget.*
import androidx.appcompat.widget.SearchView
import androidx.appcompat.widget.Toolbar
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import cz.muni.sutralog.R
import cz.muni.sutralog.data.CategoryPresentableListItem
import cz.muni.sutralog.data.RockPresentableListItem
import cz.muni.sutralog.databinding.RocksListBinding
import cz.muni.sutralog.filter.FilterColumns
import cz.muni.sutralog.filter.RockFilter
import cz.muni.sutralog.repository.CategoryRepository
import cz.muni.sutralog.repository.RockRepository
import cz.muni.sutralog.sorter.RockSorter
import cz.muni.sutralog.sorter.SortColumns
import cz.muni.sutralog.sorter.SortOrder
import cz.muni.sutralog.ui.detail.RockDetailFragmentArgs
import cz.muni.sutralog.ui.detail.RockDetailFragmentDirections
import java.time.LocalDate
import java.util.*

class RockListFragment : Fragment() {

    private lateinit var binding: RocksListBinding
    private lateinit var adapter: RockAdapter
    private var filter: RockFilter = RockFilter()
    private var sorter: RockSorter = RockSorter()

    //all rocks from db (all or rocks with given categoryId)
    private var allRocks: List<RockPresentableListItem> = mutableListOf()

    //filtered and sorted rocks
    private var rocks: List<RockPresentableListItem> = mutableListOf()
    private var category: CategoryPresentableListItem? = null
    private lateinit var filterDialog: Dialog
    private lateinit var sortDialog: Dialog
    private lateinit var toolbar: Toolbar
    private var showAllRocks: Boolean = false

    private val rockRepository: RockRepository by lazy {
        RockRepository(requireContext())
    }

    private val categoryRepository: CategoryRepository by lazy {
        CategoryRepository(requireContext())
    }

    override fun onCreateView(
        inflater: LayoutInflater,
        container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        if (!this::binding.isInitialized) {
            binding = RocksListBinding.inflate(LayoutInflater.from(context), container, false)
        }
        return binding.root
    }

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

        val categoryId = RockListFragmentArgs.fromBundle(requireArguments()).categoryId
        showAllRocks = RockListFragmentArgs.fromBundle(requireArguments()).allRocks
        allRocks = if (showAllRocks) {
            rockRepository.getAllRocks()
        } else {
            rockRepository.getRocksByCategoryId(categoryId)
        }

        if (!showAllRocks) {
            binding.addRockButton.visibility = View.VISIBLE
            category = categoryRepository.getCategoryById(categoryId)
            binding.addRockButton.setOnClickListener {
                findNavController()
                    .navigate(
                        RockListFragmentDirections
                            .actionRockListToRockEdit(
                                rock = RockPresentableListItem(
                                    categoryId = category!!.id,
                                    color = category!!.color,
                                    name = ""
                                ),
                                add = true
                            )
                    )
            }
        }

        initFilterDialog()
        initSortDialog()
        initAdapter()
        setupToolbar()
        performFiltering()
        performSorting()
        submitList()
    }

    private fun performFiltering() {
        rocks = filter.filterRockList(allRocks)
        submitList()
    }

    private fun performSorting() {
        rocks = sorter.sortRockList(rocks)
        submitList()
    }

    private fun submitList() {
        adapter.submitList(rocks)
    }

    private fun deleteRock(item: RockPresentableListItem) {
        rockRepository.deleteRock(item)
        var index = rocks.indexOf(item)
        allRocks = allRocks.minus(item)
        rocks = rocks.minus(item)
        adapter.removeItem(index)
    }

    private fun initSortDialog() {
        if (this::sortDialog.isInitialized) {
            return
        }

        sortDialog = Dialog(requireContext())
        sortDialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
        sortDialog.setContentView(R.layout.sort_bs_dialog)

        val radioGroup = sortDialog.findViewById<RadioGroup>(R.id.sort_radio_group)
        radioGroup.setOnCheckedChangeListener { _, i ->
            when (i) {
                R.id.asc_button -> sorter.order = SortOrder.ASC
                R.id.desc_button -> sorter.order = SortOrder.DESC
            }
            performSorting()
        }

        val spinner = sortDialog.findViewById<Spinner>(R.id.spinner)

        spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onItemSelected(
                parent: AdapterView<*>,
                view: View?,
                position: Int,
                id: Long
            ) {
                sorter.selectedColumn =
                    SortColumns.valueOf(parent.getItemAtPosition(position).toString())

                performSorting()
            }

            override fun onNothingSelected(parent: AdapterView<*>?) {}
        }

        val aa = ArrayAdapter(
            requireContext(),
            R.layout.spinner_item,
            SortColumns.values()
        )
        aa.setDropDownViewResource(R.layout.spinner_item)

        spinner.adapter = aa

        sortDialog.window?.setLayout(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.WRAP_CONTENT
        )
        sortDialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        sortDialog.window?.attributes?.windowAnimations = R.style.DialogAnimation
        sortDialog.window?.setGravity(Gravity.BOTTOM)
    }

    private fun initFilterDialog() {
        if (this::filterDialog.isInitialized) {
            return
        }

        filterDialog = Dialog(requireContext())
        filterDialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
        filterDialog.setContentView(R.layout.filter_bs_dialog)

        val selectFromDate = filterDialog.findViewById<EditText>(R.id.from_date)
        val selectToDate = filterDialog.findViewById<EditText>(R.id.to_date)

        val calendar = Calendar.getInstance()
        val (yearNow, monthNow, dayNow) = Triple(
            calendar.get(Calendar.YEAR),
            calendar.get(Calendar.MONTH),
            calendar.get(Calendar.DAY_OF_MONTH)
        )

        selectFromDate.setOnClickListener {
            val (year, month, day) = Triple(
                filter.fromDate?.year,
                filter.fromDate?.month?.ordinal,
                filter.fromDate?.dayOfMonth
            )

            val datePickerDialog = DatePickerDialog(
                requireContext(), R.style.DatePicker,
                { _, selectedYear, selectedMonth, selectedDay ->
                    filter.fromDate = LocalDate.of(selectedYear, selectedMonth + 1, selectedDay)
                    performFiltering()
                    selectFromDate.setText("${selectedDay}.${(selectedMonth + 1)}.${selectedYear}")
                },
                year ?: yearNow,
                month ?: monthNow,
                day ?: dayNow
            )
            datePickerDialog.setButton(
                DialogInterface.BUTTON_NEUTRAL, "Reset"
            ) { _, _ ->
                selectFromDate.setText("From date")
                filter.resetFromDate()
                performFiltering()
            }
            datePickerDialog.show()
        }

        selectToDate.setOnClickListener {
            val (year, month, day) = Triple(
                filter.toDate?.year,
                filter.toDate?.month?.ordinal,
                filter.toDate?.dayOfMonth
            )
            val datePickerDialog = DatePickerDialog(
                requireContext(), R.style.DatePicker,
                { _, selectedYear, selectedMonth, selectedDay ->
                    filter.toDate = LocalDate.of(selectedYear, selectedMonth + 1, selectedDay)
                    performFiltering()
                    selectToDate.setText("${selectedDay}.${(selectedMonth + 1)}.${selectedYear}")
                },
                year ?: yearNow,
                month ?: monthNow,
                day ?: dayNow
            )
            datePickerDialog.setButton(
                DialogInterface.BUTTON_NEUTRAL, "Reset"
            ) { _, _ ->
                selectToDate.setText("To date")
                filter.resetToDate()
                performFiltering()
            }
            datePickerDialog.show()
        }

        val spinner = filterDialog.findViewById<Spinner>(R.id.spinner)
        spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
            override fun onItemSelected(
                parent: AdapterView<*>,
                view: View?,
                position: Int,
                id: Long
            ) {
                filter.selectedColumn =
                    FilterColumns.valueOf(parent.getItemAtPosition(position).toString())
                val columnSearchKey = filterDialog.findViewById<EditText>(R.id.column_search_key)
                columnSearchKey.isEnabled = filter.selectedColumn != FilterColumns.None

                performFiltering()
            }

            override fun onNothingSelected(parent: AdapterView<*>?) {}
        }

        val aa = ArrayAdapter(
            requireContext(),
            R.layout.spinner_item,
            FilterColumns.values()
        )
        aa.setDropDownViewResource(R.layout.spinner_item)
        spinner.adapter = aa

        val columnSearchKey = filterDialog.findViewById<EditText>(R.id.column_search_key)

        columnSearchKey.addTextChangedListener(object : TextWatcher {
            override fun afterTextChanged(s: Editable) {
                if (s.toString().isNotEmpty() && s.toString().isBlank()) {
                    columnSearchKey.setText("")
                    return
                }
                filter.columnSearchKey = s.toString()
                performFiltering()
            }

            override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) {}

            override fun onTextChanged(s: CharSequence?, start: Int, before: Int, count: Int) {}
        })

        val resetButton = filterDialog.findViewById<Button>(R.id.reset_button)
        resetButton.setOnClickListener {
            filter.resetFilter()

            selectFromDate.setText("From date")
            selectToDate.setText("To Date")
            columnSearchKey.setText("")
            spinner.setSelection(0)

            performFiltering()
        }

        filterDialog.window?.setLayout(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.WRAP_CONTENT
        )
        filterDialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        filterDialog.window?.attributes?.windowAnimations = R.style.DialogAnimation
        filterDialog.window?.setGravity(Gravity.BOTTOM)
    }

    private fun showRockDialog(item: RockPresentableListItem): Boolean {
        val dialog = Dialog(requireContext())
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
        dialog.setContentView(R.layout.bs_rock_options)

        val editLayout = dialog.findViewById<LinearLayout>(R.id.edit_layout)
        val removeLayout = dialog.findViewById<LinearLayout>(R.id.remove_layout)

        editLayout.setOnClickListener {
            dialog.hide()
            findNavController()
                .navigate(
                    RockListFragmentDirections
                        .actionRockListToRockEdit(item)
                )
        }

        removeLayout.setOnClickListener {
            dialog.hide()
            AlertDialog.Builder(requireContext(), R.style.DialogTheme)
                .setMessage("Opravdu smazat?")
                .setCancelable(false)
                .setNegativeButton("Zrušit") { dialogInterface: DialogInterface, i: Int ->
                    dialogInterface.dismiss()
                }
                .setPositiveButton("Smazat") { dialogInterface: DialogInterface, i: Int ->
                    deleteRock(item)
                }
                .show()
        }

        dialog.show()
        dialog.window?.setLayout(
            ViewGroup.LayoutParams.MATCH_PARENT,
            ViewGroup.LayoutParams.WRAP_CONTENT
        )
        dialog.window?.setBackgroundDrawable(ColorDrawable(Color.TRANSPARENT))
        dialog.window?.attributes?.windowAnimations = R.style.DialogAnimation
        dialog.window?.setGravity(Gravity.BOTTOM)
        return true
    }


    private fun setToolbarTitle() {
        binding.toolbar.title = category?.name ?: "Rocks"
    }

    private fun initAdapter() {
        if (this::adapter.isInitialized) {
            return
        }

        adapter = RockAdapter(
            onItemClick = {
                findNavController()
                    .navigate(
                        RockListFragmentDirections
                            .actionRockListToRockDetail(it.id)
                    )
            },
            onItemLongClick = {
                showRockDialog(it)
            }
        )

        binding.recyclerView.adapter = adapter
    }

    private fun setupToolbar() {
        setToolbarTitle()

        if (this::toolbar.isInitialized) {
            return
        }

        toolbar = binding.toolbar

        if (showAllRocks) {
            toolbar.menu.clear()
            binding.toolbar.inflateMenu(R.menu.all_rocks_menu)
        }

        val searchItem = toolbar.menu.findItem(R.id.search)
        val searchView = searchItem.actionView as SearchView

        searchView.setOnQueryTextListener(object : SearchView.OnQueryTextListener {
            override fun onQueryTextSubmit(query: String?): Boolean {

                return false
            }

            override fun onQueryTextChange(newText: String?): Boolean {
                if (newText.toString().isNotEmpty() && newText.toString().trim().isEmpty()) {
                    searchView.setQuery("", false)
                    return false
                }
                filter.nameSearchKey = newText ?: ""
                performFiltering()
                return false
            }
        })

        toolbar.setOnMenuItemClickListener {
            when (it.itemId) {
                R.id.filter -> showFilterDialog()
                R.id.sort -> showSortDialog()
                R.id.edit_category -> showEditCategory()
                R.id.remove_category -> removeCategory()
            }
            true
        }

        toolbar.setNavigationOnClickListener {
            findNavController().navigateUp()
        }
    }

    private fun showEditCategory() {
        findNavController().navigate(
            RockListFragmentDirections
                .actionRockListFragmentToCategoryEditFragment(category!!)
        )
    }

    private fun showFilterDialog() {
        filterDialog.show()
    }

    private fun showSortDialog() {
        sortDialog.show()
    }

    private fun removeCategory() {
        AlertDialog.Builder(requireContext())
            .setMessage("Opravdu smazat?")
            .setCancelable(false)
            .setNegativeButton("Zrušit") { dialogInterface: DialogInterface, i: Int ->
                dialogInterface.dismiss()
            }
            .setPositiveButton("Smazat") { dialogInterface: DialogInterface, i: Int ->
                AlertDialog.Builder(requireContext())
                    .setMessage("Budou smazány všechny kameny v této kategorii, opravdu smazat?")
                    .setCancelable(false)
                    .setNegativeButton("Zrušit") { dialogInterface: DialogInterface, i: Int ->
                        dialogInterface.dismiss()
                    }
                    .setPositiveButton("Smazat") { dialogInterface: DialogInterface, i: Int ->
                        categoryRepository.deleteCategory(category!!)
                    }
                    .show()
            }
            .show()
    }
}