package fr.iut.ouafff.ui.fragment

import android.content.Context
import android.os.Bundle
import android.provider.ContactsContract
import android.text.format.DateFormat
import android.view.*
import android.widget.EditText
import android.widget.RatingBar
import android.widget.Spinner
import android.widget.TextView
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 fr.iut.ouafff.R
import fr.iut.ouafff.data.Dog
import fr.iut.ouafff.data.NEW_DOG_ID
import fr.iut.ouafff.data.persistance.DogDatabase
import fr.iut.ouafff.data.persistance.converter.toGender
import fr.iut.ouafff.ui.dialog.DatePickerFragment
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 lateinit var dog: Dog
    private var dogId: Long = NEW_DOG_ID

    private lateinit var editDogName: EditText
    private lateinit var editDogBreed: EditText
    private lateinit var spinnerGender: Spinner
    private lateinit var editDogWeight: EditText
    private lateinit var ratingbarAggressiveness: RatingBar
    private lateinit var textDogOwner: TextView
    private lateinit var textDogAdmissionDate: TextView


    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

        dog = if (dogId == NEW_DOG_ID) {
            requireActivity().setTitle(R.string.title_add_dog)
            Dog()
        } else {
            DogDatabase.getInstance().dogDAO().findById(dogId)
        }
    }

    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 view = inflater.inflate(R.layout.fragment_dog, container, false)
        editDogName = view.findViewById(R.id.edit_dog_name)
        editDogBreed = view.findViewById(R.id.edit_dog_breed)
        spinnerGender = view.findViewById(R.id.spinner_gender)
        editDogWeight = view.findViewById(R.id.edit_dog_weight)
        ratingbarAggressiveness = view.findViewById(R.id.ratingbar_aggressiveness)
        textDogOwner = view.findViewById(R.id.text_dog_owner)
        textDogAdmissionDate = view.findViewById(R.id.text_dog_admission_date)

        updateViewFromCurrentDog()

        textDogOwner.setOnClickListener {
            pickOwner.launch()
        }

        textDogAdmissionDate.setOnClickListener {
            val dateDialog = DatePickerFragment.newInstance(REQUEST_DATE, dog.admissionDate)
            dateDialog.show(parentFragmentManager, DIALOG_DATE)
        }

        return view
    }


    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 updateViewFromCurrentDog() {
        editDogName.setText(dog.name)
        editDogBreed.setText(dog.breed)
        spinnerGender.setSelection(dog.gender.ordinal)
        editDogWeight.setText(dog.weight.toString())
        ratingbarAggressiveness.rating = dog.aggressiveness.toFloat()
        textDogOwner.text = dog.owner
        dog.admissionDate?.let {
            textDogAdmissionDate.text = DateFormat.getDateFormat(activity).format(it)
        }
    }


    private fun saveDog() {
        val dogName = editDogName.text.trim()
        val dogWeight = editDogWeight.text.trim()
        if (dogName.isEmpty() || dogWeight.isEmpty() || dogWeight == ".") {
            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
        }

        dog.name = dogName.toString()
        dog.breed = editDogBreed.text.toString()
        dog.gender = spinnerGender.selectedItemPosition.toGender()
        dog.weight = dogWeight.toString().toFloat()
        dog.aggressiveness = ratingbarAggressiveness.rating.toInt()

        if (dog.id == NEW_DOG_ID)
            DogDatabase.getInstance().dogDAO().insert(dog)
        else
            DogDatabase.getInstance().dogDAO().update(dog)

        listener?.onDogSaved()
    }


    private fun deleteDog() {
        if (dogId != NEW_DOG_ID) {
            DogDatabase.getInstance().dogDAO().delete(dog)
            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)
            dog.admissionDate = Date().apply { time = cal.timeInMillis }
            textDogAdmissionDate.text = dog.admissionDate?.let {
                DateFormat.getDateFormat(activity).format(it)
            } ?: ""
        }
    }


    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()
                        dog.owner = it.getString(0)
                    }
                    it.close()
                }
                textDogOwner.text = dog.owner
            }
        }


    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
    }
}
