package fr.iut.ouafff.ui.fragment

import android.content.Context
import android.os.Bundle
import android.provider.ContactsContract
import android.view.*
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.result.launch
import androidx.appcompat.app.AlertDialog
import androidx.core.os.bundleOf
import androidx.core.view.MenuProvider
import androidx.fragment.app.Fragment
import androidx.fragment.app.setFragmentResultListener
import androidx.lifecycle.Lifecycle
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.get
import fr.iut.ouafff.R
import fr.iut.ouafff.data.NEW_DOG_ID
import fr.iut.ouafff.databinding.FragmentDogBinding
import fr.iut.ouafff.ui.dialog.DatePickerFragment
import fr.iut.ouafff.ui.utils.viewModelFactory
import fr.iut.ouafff.ui.viewmodel.DogViewModel
import java.util.Date
import java.util.Calendar

class DogFragment : Fragment() {

    companion object {
        private const val EXTRA_DOG_ID = "fr.iut.ouafff.extra_dogid"
        private const val REQUEST_DATE = "DateRequest"
        private const val DIALOG_DATE = "DateDialog"

        fun newInstance(dogId: Long) = DogFragment().apply {
            arguments = bundleOf(EXTRA_DOG_ID to dogId)
        }
    }

    private var dogId: Long = NEW_DOG_ID
    private lateinit var dogVM: DogViewModel


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

        setFragmentResultListener(REQUEST_DATE, this::onAdmissionDateChanged)

        dogId = savedInstanceState?.getLong(EXTRA_DOG_ID) ?: arguments?.getLong(EXTRA_DOG_ID)
                ?: NEW_DOG_ID


        if (dogId == NEW_DOG_ID) {
            requireActivity().setTitle(R.string.title_add_dog)
        }

        dogVM = ViewModelProvider(this, viewModelFactory { DogViewModel(dogId) }).get()
    }

    override fun onSaveInstanceState(outState: Bundle) {
        super.onSaveInstanceState(outState)
        outState.putLong(EXTRA_DOG_ID, dogId)
    }


    override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?,
        savedInstanceState: Bundle?
    ): View {
        val binding = FragmentDogBinding.inflate(inflater)
        binding.dogVM = dogVM
        binding.lifecycleOwner = viewLifecycleOwner
        binding.textDogOwner.setOnClickListener {
            pickOwner.launch()
        }

        binding.textDogAdmissionDate.setOnClickListener {
            val dateDialog =
                DatePickerFragment.newInstance(REQUEST_DATE, dogVM.admissionDateLiveData.value)
            dateDialog.show(parentFragmentManager, DIALOG_DATE)
        }

        return binding.root
    }


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


    private fun setupMenu() {
        requireActivity().addMenuProvider(object : MenuProvider {
            override fun onPrepareMenu(menu: Menu) {
                super.onPrepareMenu(menu)
                if (dogId == NEW_DOG_ID) {
                    menu.findItem(R.id.action_delete)?.isVisible = false
                }
            }

            override fun onCreateMenu(menu: Menu, menuInflater: MenuInflater) {
                menuInflater.inflate(R.menu.fragment_dog, menu)
            }

            override fun onMenuItemSelected(menuItem: MenuItem): Boolean {
                return when (menuItem.itemId) {
                    R.id.action_save -> {
                        saveDog()
                        true
                    }
                    R.id.action_delete -> {
                        deleteDog()
                        true
                    }
                    else -> false
                }
            }

        }, viewLifecycleOwner, Lifecycle.State.RESUMED)
    }


    private fun saveDog() {
        if (dogVM.saveDog() == true) {
            listener?.onDogSaved()
        } else {
            AlertDialog.Builder(requireActivity())
                .setTitle(R.string.create_dog_error_dialog_title)
                .setMessage(R.string.create_dog_error_message)
                .setNeutralButton(android.R.string.ok, null)
                .show()
            return
        }
    }


    private fun deleteDog() {
        if (dogId != NEW_DOG_ID) {
            dogVM.deleteDog()
            listener?.onDogDeleted()
        }
    }


    private fun onAdmissionDateChanged(requestKey: String, bundle: Bundle) {
        if (requestKey == REQUEST_DATE) {
            val year = bundle.getInt(DatePickerFragment.EXTRA_YEAR)
            val month = bundle.getInt(DatePickerFragment.EXTRA_MONTH)
            val day = bundle.getInt(DatePickerFragment.EXTRA_DAY)

            val cal = Calendar.getInstance()
            cal.set(year, month, day)
            dogVM.admissionDateLiveData.value = Date().apply { time = cal.timeInMillis }
        }
    }


    private val pickOwner =
        registerForActivityResult(ActivityResultContracts.PickContact()) { contactUri ->
            if (contactUri != null) {
                val queryFields = arrayOf(ContactsContract.Contacts.DISPLAY_NAME)
                val contactCursor = activity?.contentResolver?.query(
                    contactUri, queryFields, null,
                    null, null
                )

                contactCursor?.let {
                    if (it.count != 0) {
                        it.moveToFirst()
                        dogVM.ownerLiveData.value = it.getString(0)
                    }
                    it.close()
                }
            }
        }


    interface OnInteractionListener {
        fun onDogSaved()
        fun onDogDeleted()
    }

    private var listener: OnInteractionListener? = null


    override fun onAttach(context: Context) {
        super.onAttach(context)
        if (context is OnInteractionListener) {
            listener = context
        } else {
            throw RuntimeException("$context must implement OnInteractionListener")
        }
    }


    override fun onDetach() {
        super.onDetach()
        listener = null
    }
}
