package com.github.libretube.ui.dialogs

import android.app.Dialog
import android.os.Bundle
import android.widget.Toast
import androidx.core.os.bundleOf
import androidx.core.view.isVisible
import androidx.fragment.app.DialogFragment
import androidx.fragment.app.setFragmentResult
import androidx.lifecycle.lifecycleScope
import com.github.libretube.R
import com.github.libretube.api.PlaylistsHelper
import com.github.libretube.repo.LocalPlaylistsRepository
import com.github.libretube.constants.IntentData
import com.github.libretube.databinding.DialogCreatePlaylistBinding
import com.github.libretube.extensions.parcelable
import com.github.libretube.extensions.toastFromMainDispatcher
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.launch
import kotlinx.coroutines.withContext
import okhttp3.HttpUrl.Companion.toHttpUrlOrNull

class CreatePlaylistDialog : DialogFragment() {
    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val binding = DialogCreatePlaylistBinding.inflate(layoutInflater)

        binding.createPlaylistSpinner.items = listOf(
            getString(R.string.createNewPlaylist),
            getString(R.string.clonePlaylist)
        )
        binding.createPlaylistSpinner.setOnSelectionChangeListener { position ->
            binding.createPlayistContainerView.isVisible = position == 0
            binding.clonePlaylistContainerView.isVisible = position == 1
        }

        binding.clonePlaylist.setOnClickListener {
            val playlistUrl = binding.playlistUrl.text.toString().toHttpUrlOrNull()
            val appContext = context?.applicationContext

            playlistUrl?.queryParameter("list")?.let { listId ->
                lifecycleScope.launch {
                    requireDialog().hide()
                    // Try network clone first, fallback to local playlist creation on failure
                    val playlistId = withContext(Dispatchers.IO) {
                        runCatching {
                            PlaylistsHelper.clonePlaylist(listId)
                        }.getOrNull()
                    } ?: withContext(Dispatchers.IO) {
                        // fallback: create a local playlist with generic name
                        LocalPlaylistsRepository().createPlaylist("Cloned playlist")
                    }

                    playlistId?.let {
                        setFragmentResult(
                            CREATE_PLAYLIST_DIALOG_REQUEST_KEY,
                            bundleOf(
                                IntentData.playlistTask to true,
                                IntentData.playlistId to playlistId
                            ),
                        )
                    }

                    appContext?.toastFromMainDispatcher(R.string.playlistCloned)
                    dismiss()
                }
            } ?: run {
                Toast.makeText(context, R.string.invalid_url, Toast.LENGTH_SHORT).show()
            }
        }

        binding.createNewPlaylist.setOnClickListener {
            val appContext = context?.applicationContext
            val listName = binding.playlistName.text?.toString()
            if (!listName.isNullOrEmpty()) {
                // avoid creating the same playlist multiple times by spamming the button
                binding.createNewPlaylist.setOnClickListener(null)
                lifecycleScope.launch {
                    requireDialog().hide()

                    // Try to create via PlaylistsHelper (may use network), but fallback to local repository
                    val playlistId = withContext(Dispatchers.IO) {
                        runCatching {
                            PlaylistsHelper.createPlaylist(listName)
                        }.getOrNull()
                    } ?: withContext(Dispatchers.IO) {
                        LocalPlaylistsRepository().createPlaylist(listName)
                    }

                    // If the dialog was opened from AddToPlaylist, the creator may have passed
                    // a `videoInfo` in the arguments. If present, insert the video into the new playlist.
                    val createdAndAdded = withContext(Dispatchers.IO) {
                        val videoInfo = arguments?.parcelable<com.github.libretube.api.obj.StreamItem>(IntentData.videoInfo)
                        if (videoInfo != null && playlistId != null) {
                            // try network add, fallback to local add
                            runCatching {
                                PlaylistsHelper.addToPlaylist(playlistId, videoInfo)
                            }.isSuccess || runCatching {
                                LocalPlaylistsRepository().addToPlaylist(playlistId, videoInfo)
                            }.isSuccess
                        } else false
                    }

                    appContext?.toastFromMainDispatcher(
                        when {
                            playlistId == null -> R.string.unknown_error
                            createdAndAdded -> R.string.added_to_playlist
                            else -> R.string.playlistCreated
                        }
                    )

                    playlistId?.let {
                        setFragmentResult(
                            CREATE_PLAYLIST_DIALOG_REQUEST_KEY,
                            bundleOf(
                                IntentData.playlistTask to true,
                                IntentData.playlistId to playlistId
                            )
                        )
                    }
                    dismiss()
                }
            } else {
                Toast.makeText(context, R.string.emptyPlaylistName, Toast.LENGTH_LONG).show()
            }
        }

        binding.cancelCreate.setOnClickListener {
            dialog?.cancel()
        }

        binding.cancelClone.setOnClickListener {
            dialog?.cancel()
        }

        return MaterialAlertDialogBuilder(requireContext())
            .setTitle(R.string.createPlaylist)
            .setView(binding.root)
            .show()
    }

    companion object {
        const val CREATE_PLAYLIST_DIALOG_REQUEST_KEY = "create_playlist_dialog_request_key"
    }
}
