package cz.muni.sutralog.ui.detail

import android.Manifest
import android.annotation.SuppressLint
import android.app.Activity
import android.app.AlertDialog
import android.app.DatePickerDialog
import android.app.Dialog
import android.content.ContentValues
import android.content.DialogInterface
import android.content.Intent
import android.content.pm.PackageManager
import android.graphics.Color
import android.graphics.drawable.ColorDrawable
import android.net.Uri
import android.os.Build
import android.os.Bundle
import android.provider.MediaStore
import android.view.*
import android.widget.ArrayAdapter
import android.widget.LinearLayout
import android.widget.TextView
import android.widget.Toast
import androidx.activity.result.contract.ActivityResultContracts
import androidx.core.content.PermissionChecker.PERMISSION_DENIED
import androidx.core.content.PermissionChecker.checkSelfPermission
import androidx.fragment.app.Fragment
import androidx.navigation.fragment.findNavController
import com.skydoves.colorpickerview.ColorEnvelope
import com.skydoves.colorpickerview.ColorPickerDialog
import com.skydoves.colorpickerview.flag.FlagMode
import com.skydoves.colorpickerview.listeners.ColorEnvelopeListener
import cz.muni.sutralog.R
import cz.muni.sutralog.data.CategoryPresentableListItem
import cz.muni.sutralog.data.PhotoPresentableListItem
import cz.muni.sutralog.data.RockPresentableListItem
import cz.muni.sutralog.databinding.RockEditBinding
import cz.muni.sutralog.lib.ColorPickerFlag
import cz.muni.sutralog.lib.SutralogStaticLib.Companion.dateToString
import cz.muni.sutralog.lib.SutralogStaticLib.Companion.stringToDate
import cz.muni.sutralog.repository.CategoryRepository
import cz.muni.sutralog.repository.PhotoRepository
import cz.muni.sutralog.repository.RockRepository
import cz.muni.sutralog.ui.list.PhotoAdapter
import java.util.*


class RockEditFragment  : Fragment() {

    private lateinit var binding: RockEditBinding
    private lateinit var adapter: PhotoAdapter

    private val rockRepository: RockRepository by lazy {
        RockRepository(requireContext())
    }
    private val categoryRepository: CategoryRepository by lazy {
        CategoryRepository(requireContext())
    }
    private val photoRepository: PhotoRepository by lazy {
        PhotoRepository(requireContext())
    }

    private var create: Boolean = false
    private var imageUri: Uri? = null
    private lateinit var photos : List<PhotoPresentableListItem>

    override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        binding = RockEditBinding.inflate(layoutInflater, container, false)
        return binding.root
    }

    companion object {
        private val GALLERY_CODE = 1001;
        private val CAMERA_CODE = 1002;
    }

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

        val rock = RockEditFragmentArgs.fromBundle(requireArguments()).rock
        create = RockEditFragmentArgs.fromBundle(requireArguments()).add

        adapter = PhotoAdapter(
            onItemClick = {

            },
            onItemLongClick = {
                showPhotoDialog(it)
            }
        )

        binding.rockImageRecyclerView.adapter = adapter

        setCurrentRockValues(rock)
        initDatePicker(rock)
        initColorPicker(rock)

        photos = photoRepository.getPhotosByRockId(rock.id)

        binding.toolbar.title = if (create) "Nový kámen" else "Upravit kámen"

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

        binding.toolbar.setOnMenuItemClickListener {
            when (it.itemId) {
                R.id.done -> {
                    saveValues(rock)
                    findNavController().navigateUp()
                }
            }
            true
        }

        binding.changeImageButton.setOnClickListener {
            val builder = AlertDialog.Builder(requireContext())
            builder.setMessage("Vyberte způsob přidání fotografie")
            builder.setPositiveButton("Galerie"){dialogInterface, which ->
                checkPermissionsAndOpenGallery()
            }
            builder.setNegativeButton("Fotoaparát"){dialogInterface, which ->
                checkPermissionsAndOpenCamera()
            }
            val alertDialog: AlertDialog = builder.create()
            alertDialog.show()
        }
    }

    private fun checkPermissionsAndOpenCamera() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
            if (checkSelfPermission(requireContext(), Manifest.permission.READ_EXTERNAL_STORAGE) == PERMISSION_DENIED ||
                checkSelfPermission(requireContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PERMISSION_DENIED ||
                checkSelfPermission(requireContext(), Manifest.permission.CAMERA) == PERMISSION_DENIED) {
                val permissions = arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE, Manifest.permission.CAMERA)
                requestPermissions(permissions, CAMERA_CODE)
            } else {
                openCamera();
            }
        } else {
            openCamera();
        }
    }


    private fun openCamera() {
        val values = ContentValues()
        values.put(MediaStore.Images.Media.TITLE, "Take a picture")
        imageUri = activity?.contentResolver?.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)

        // Create camera intent
        val intent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
        intent.putExtra(MediaStore.EXTRA_OUTPUT, imageUri)

        // Launch intent
        openCameraLauncher.launch(intent)
    }

    private var openCameraLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            var imagePath = getImagePath(imageUri.toString().contains("content://media"), false, imageUri!!.path!!)
            if (imagePath == null) imagePath = getImagePath(false, imageUri.toString().contains("file://storage"), imageUri!!.path!!)

            addPhoto(imagePath!!)
        }
    }

    fun getImagePath(isMedia: Boolean, isStorage: Boolean, path: String): String? {
        if (isMedia) {
            return "content://media$path"
        }
        if (isStorage) {
            return "file://storage$path"
        }
        return null
    }

    private fun addPhoto(path: String) {
        val photo = PhotoPresentableListItem()
        photo.path = path
        photos = photos.plus(photo)
        adapter.addItem(photo)
    }

    private fun checkPermissionsAndOpenGallery() {
        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M){
            if (checkSelfPermission(requireContext(), Manifest.permission.READ_EXTERNAL_STORAGE) == PERMISSION_DENIED ||
                checkSelfPermission(requireContext(), Manifest.permission.WRITE_EXTERNAL_STORAGE) == PERMISSION_DENIED){
                val permissions = arrayOf(Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE)
                requestPermissions(permissions, RockEditFragment.GALLERY_CODE)
            } else {
                chooseImageGallery();
            }
        } else {
            chooseImageGallery();
        }
    }

    private fun chooseImageGallery() {
        val intent = Intent(Intent.ACTION_PICK)
        intent.type = "image/*"
        openGalleryLauncher.launch(intent)
    }

    override fun onRequestPermissionsResult(
        requestCode: Int,
        permissions: Array<out String>,
        grantResults: IntArray
    ) {
        super.onRequestPermissionsResult(requestCode, permissions, grantResults)
        when(requestCode){
            GALLERY_CODE -> {
                if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                    chooseImageGallery()
                } else {
                    Toast.makeText(requireContext(),"Přístup nebyl povolen.", Toast.LENGTH_SHORT).show()
                }
            }
            CAMERA_CODE -> {
                if (grantResults.isNotEmpty() && grantResults[0] == PackageManager.PERMISSION_GRANTED){
                    openCamera()
                } else {
                    Toast.makeText(requireContext(),"Přístup nebyl povolen.", Toast.LENGTH_SHORT).show()
                }
            }
        }
    }


    var openGalleryLauncher = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) { result ->
        if (result.resultCode == Activity.RESULT_OK) {
            val data: Intent? = result.data
            var imagePath = getImagePath(data.toString().contains("content://media"), false, data?.data?.path!!)
            if (imagePath == null) imagePath = getImagePath(false, data.toString().contains("file://storage"), data?.data?.path!!)

            addPhoto(imagePath!!)
        }
    }

    private fun saveValues(oldRock: RockPresentableListItem) {
        oldRock.name = binding.rockName.text.toString()
        oldRock.categoryId = (binding.rockCategory.selectedItem as CategoryPresentableListItem).id
        binding.rockCount.text.toString().let {
            oldRock.count = if (it == "") null else it.toInt()
        }
        binding.rockDate.text.toString().let {
            oldRock.date = if (it == "") null else stringToDate(it)
        }
        oldRock.locality = binding.rockLocality.text.toString()
        binding.rockCoordinatesLatitude.text.toString().let {
            oldRock.latitude = if (it == "") null else it.toDouble()
        }
        binding.rockCoordinatesLongitude.text.toString().let {
            oldRock.longitude = if (it == "") null else it.toDouble()
        }
        oldRock.where = binding.rockWhere.text.toString()
        oldRock.from = binding.rockFrom.text.toString()
        oldRock.description = binding.rockDescription.text.toString()
        oldRock.comment = binding.rockComment.text.toString()
        oldRock.color = (binding.rockColorView.background as ColorDrawable).color

        var rockId = oldRock.id

        if(create){
            rockId = rockRepository.insertRock(oldRock)
        } else {
            rockRepository.updateRock(oldRock)
        }

        val oldPhotos = photoRepository.getPhotosByRockId(rockId)
        val photosToRemove = oldPhotos.minus(photos)
        photoRepository.deletePhotos(photosToRemove)
        for(photo in photos) {
            if (photo.id == 0.toLong()) {
                photo.rockId = rockId
                photoRepository.savePhoto(photo)
            }
        }
    }

    private fun initColorPicker(rock: RockPresentableListItem) {
        binding.rockColorView.setOnClickListener {
            val builder = ColorPickerDialog.Builder(requireContext(), R.style.ColorPicker)
                .setTitle("Vyber si barvu")
                .setPositiveButton("Potvrdit",
                    ColorEnvelopeListener { colorEnvelope: ColorEnvelope, fromUser: Boolean ->
                        binding.rockColorView.setBackgroundColor(colorEnvelope.color)
                })
                .setNegativeButton("Zrušit") { dialogInterface: DialogInterface, i: Int ->
                    dialogInterface.dismiss()
                }
                .setNeutralButton("Zdědit barvu vybrané kategorie") { dialogInterface: DialogInterface, i: Int ->
                    binding.rockColorView.setBackgroundColor((binding.rockCategory.selectedItem as CategoryPresentableListItem).color)
                    dialogInterface.dismiss()
                }
                //.attachAlphaSlideBar(false)
            builder.colorPickerView.setInitialColor(rock.color)
            val bubbleFlag = ColorPickerFlag(requireContext(), R.layout.color_picker_flag)
            bubbleFlag.flagMode = FlagMode.ALWAYS
            builder.colorPickerView.flagView = bubbleFlag
            builder.show()
        }
    }

    @SuppressLint("SetTextI18n")
    private fun initDatePicker(rock: RockPresentableListItem) {
        binding.rockDate.setOnClickListener {
            val calendar = Calendar.getInstance()
            val year = calendar.get(Calendar.YEAR)
            val month = calendar.get(Calendar.MONTH)
            val day = calendar.get(Calendar.DAY_OF_MONTH)
            val datePickerDialog = DatePickerDialog(requireContext(), R.style.DatePicker,
                { _, selectedYear, selectedMonth, selectedDay ->
                    binding.rockDate.text = ("${selectedDay}.${(selectedMonth + 1)}.${selectedYear}")
                },
                if (rock.date != null) rock.date!!.year else year,
                if (rock.date != null) rock.date!!.monthValue else month,
                if (rock.date != null) rock.date!!.dayOfMonth else day
            )
            datePickerDialog.show()
        };
    }

    private fun setCurrentRockValues(rock: RockPresentableListItem) {
        val category = categoryRepository.getCategoryById(rock.categoryId)
        val categories = categoryRepository.getAllCategories()

        val arrayAdapter = ArrayAdapter(requireContext(), android.R.layout.simple_list_item_1, categories)

        binding.rockName.setText(rock.name)
        binding.rockCategory.adapter = arrayAdapter
        binding.rockCategory.setSelection(categories.indexOf(category))
        rock.count?.let { binding.rockCount.setText(it.toString()) }
        rock.date?.let { binding.rockDate.text = dateToString(it) }
        binding.rockLocality.setText(rock.locality)
        rock.latitude?.let { binding.rockCoordinatesLatitude.setText(it.toString()) }
        rock.longitude?.let { binding.rockCoordinatesLongitude.setText(it.toString()) }
        binding.rockWhere.setText(rock.where)
        binding.rockFrom.setText(rock.from)
        binding.rockDescription.setText(rock.description)
        binding.rockComment.setText(rock.comment)
        binding.rockColorView.setBackgroundColor(rock.color)

        val photos = photoRepository.getPhotosByRockId(rock.id)
        if (photos.isNotEmpty()) {
            adapter.submitList(photos)
        }
    }

    private fun showPhotoDialog(item: PhotoPresentableListItem): Boolean {
        val dialog = Dialog(requireContext())
        dialog.requestWindowFeature(Window.FEATURE_NO_TITLE)
        dialog.setContentView(R.layout.bs_photo_options)

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

        removeLayout.setOnClickListener {
            dialog.hide()
            AlertDialog.Builder(requireContext())
                .setMessage("Opravdu smazat?")
                .setCancelable(false)
                .setNegativeButton("Zrušit") { dialogInterface: DialogInterface, i: Int ->
                    dialogInterface.dismiss()
                }
                .setPositiveButton("Smazat") { dialogInterface: DialogInterface, i: Int ->
                    deletePhoto(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 deletePhoto(item: PhotoPresentableListItem) {
        val index = photos.indexOf(item)
        photos = photos.minus(item)
        adapter.removeItem(index)
    }
}