/**
 *  Copyright (C) 2021 Anthony Chomienne
 *  This program is free software: you can redistribute it and/or modify it under the terms of the
 *  GNU Affero General Public License as published by the Free Software Foundation, version 3.
 *
 *  This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
 *  without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
 *  See the GNU Affero General Public License for more details.
 *
 *  You should have received a copy of the GNU Affero General Public License along with this program.
 *  If not, see <https://www.gnu.org/licenses/>
 */

package fr.mobdev.peertubelive.activity

import android.content.Intent
import android.os.Bundle
import android.view.View
import android.widget.ArrayAdapter
import android.widget.ProgressBar
import androidx.activity.result.ActivityResultLauncher
import androidx.activity.result.contract.ActivityResultContracts
import androidx.appcompat.app.AlertDialog
import androidx.appcompat.app.AppCompatActivity
import androidx.databinding.DataBindingUtil
import fr.mobdev.peertubelive.R
import fr.mobdev.peertubelive.databinding.CreateLiveBinding
import fr.mobdev.peertubelive.manager.DatabaseManager
import fr.mobdev.peertubelive.manager.InstanceManager
import fr.mobdev.peertubelive.objects.*
import fr.mobdev.peertubelive.utils.TranslationUtils
import java.util.ArrayList

class CreateLiveActivity : AppCompatActivity() {

    companion object{
        const val OAUTH_DATA = "OAUTH_DATA"
    }

    private lateinit var channels: List<ChannelData>
    private lateinit var categories: MutableMap<String, Int>
    private lateinit var licences: MutableMap<String, Int>
    private lateinit var privacies: MutableMap<String, Int>
    private lateinit var languages: MutableMap<String, String>
    private lateinit var oAuthData: OAuthData
    private lateinit var configData: ConfigData
    private var inError: Boolean = false
    private var showAdvancedSettings = true
    private lateinit var binding: CreateLiveBinding
    private lateinit var startLive: ActivityResultLauncher<Intent>

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

        oAuthData = intent.getParcelableExtra(OAUTH_DATA)!!

        binding = DataBindingUtil.setContentView(this,R.layout.create_live)

        binding.error.visibility = View.GONE
        binding.channelList.visibility = View.GONE
        binding.liveTitle.visibility = View.GONE
        binding.channel.visibility = View.GONE
        binding.title.visibility = View.GONE
        binding.titleError.visibility = View.GONE
        binding.advanceSettings.visibility = View.GONE
        binding.privacy.visibility = View.GONE
        binding.privacyList.visibility = View.GONE
        binding.saveReplayLayout.visibility = View.GONE
        binding.saveReplayInfo.visibility = View.GONE
        binding.resolution.visibility = View.GONE
        binding.resolutionList.visibility = View.GONE
        binding.liveDisabled.visibility = View.GONE

        startLive = registerForActivityResult(ActivityResultContracts.StartActivityForResult()) {
            setResult(it.resultCode)
            finish()
        }

        toggleAdvanceSettings()

        binding.goLive.isEnabled = false
        binding.advanceSettings.setOnClickListener{
            toggleAdvanceSettings()
        }
        binding.goLive.setOnClickListener {
            val title = binding.liveTitle.text.toString()
            val channel = channels[binding.channelList.selectedItemPosition].id
            var category: Int? = categories[binding.categoryList.selectedItem.toString()]!!
            val privacy = privacies[binding.privacyList.selectedItem.toString()]!!
            if (category == 0)
                category = null
            var language: String? = languages[binding.languageList.selectedItem.toString()]!!
            if (language != null && language.isEmpty())
                    language = null
            var licence: Int? = licences[binding.licenceList.selectedItem.toString()]!!
            if (licence == 0)
                licence = null

            var description: String? = binding.description.text.toString()
            if (description != null && description.isEmpty())
                description = null

            val comments = binding.commentsEnabled.isChecked
            val download = binding.downloadEnabled.isChecked
            val nsfw = binding.nsfw.isChecked
            var replay: Boolean? = null
            if (configData.saveReplayEnabled)
                replay = binding.saveReplay.isChecked

            val resolution = StreamData.STREAM_RESOLUTION.values()[binding.resolutionList.selectedItemPosition]

            val streamSettings = StreamSettings(title,channel,privacy,category,language,licence,description,comments,download,nsfw,replay,resolution)
            DatabaseManager.updateStreamSettings(this,streamSettings)
            if(title.isEmpty())
            {
                binding.titleError.visibility = View.VISIBLE
            } else {
                binding.titleError.visibility = View.GONE
                goLive(streamSettings)
            }
        }

        InstanceManager.getLiveConfig(this,oAuthData.baseUrl!!,object : InstanceManager.InstanceListener {
            override fun onSuccess(args: Bundle?) {
                configData = args?.getParcelable<ConfigData>(InstanceManager.EXTRA_DATA)!!
                updateView(null)
            }

            override fun onError(error: String?) {
                inError = true
                updateView(error)
            }

            override fun onUpdateOAuthData(oauthData: OAuthData) {
                this@CreateLiveActivity.oAuthData.updateData(oauthData)
            }
        })

        InstanceManager.getCategoryList(this,oAuthData.baseUrl!!,object : InstanceManager.InstanceListener {
            override fun onSuccess(args: Bundle?) {
                val map = args?.getSerializable(InstanceManager.EXTRA_DATA)!! as Map<String, Int>
                categories = HashMap(map.count())
                for(pair in map.entries) {
                    val stringId = TranslationUtils.getCategoryTranslationFor(pair.key)
                    if(stringId != -1)
                        categories[getString(stringId)] = pair.value
                    else
                        categories[pair.key] = pair.value
                }
                updateView(null)
            }

            override fun onError(error: String?) {
                inError = true
                updateView(error)
            }

            override fun onUpdateOAuthData(oauthData: OAuthData) {
                this@CreateLiveActivity.oAuthData.updateData(oauthData)
            }
        })

        InstanceManager.getUserChannelList(this,oAuthData.baseUrl!!,oAuthData, object : InstanceManager.InstanceListener {
            override fun onSuccess(args: Bundle?) {
                channels = args?.getParcelableArrayList<ChannelData>(InstanceManager.EXTRA_DATA)!!
                updateView(null)
            }

            override fun onError(error: String?) {
                inError = true
                updateView(error)
            }

            override fun onUpdateOAuthData(oauthData: OAuthData) {
                this@CreateLiveActivity.oAuthData.updateData(oauthData)
            }
        })

        InstanceManager.getPrivacyList(this,oAuthData.baseUrl!!, object : InstanceManager.InstanceListener {
            override fun onSuccess(args: Bundle?) {
                val map = args?.getSerializable(InstanceManager.EXTRA_DATA)!! as Map<String, Int>
                privacies = HashMap(map.count())
                for(pair in map.entries) {
                    val stringId = TranslationUtils.getPrivacyTranslationFor(pair.key)
                    if(stringId != -1)
                        privacies[getString(stringId)] = pair.value
                    else
                        privacies[pair.key] = pair.value
                }
                updateView(null)
            }

            override fun onError(error: String?) {
                inError = true
                updateView(error)
            }

            override fun onUpdateOAuthData(oauthData: OAuthData) {
                this@CreateLiveActivity.oAuthData.updateData(oauthData)
            }
        })

        InstanceManager.getLicencesList(this,oAuthData.baseUrl!!, object : InstanceManager.InstanceListener {
            override fun onSuccess(args: Bundle?) {
                var map = args?.getSerializable(InstanceManager.EXTRA_DATA)!! as Map<String, Int>
                licences = HashMap(map.count())
                for(pair in map.entries) {
                    val stringId = TranslationUtils.getLicenceTranslationFor(pair.key)
                    if(stringId != -1)
                        licences[getString(stringId)] = pair.value
                    else
                        licences[pair.key] = pair.value
                }
                updateView(null)
            }

            override fun onError(error: String?) {
                inError = true
                updateView(error)
            }

            override fun onUpdateOAuthData(oauthData: OAuthData) {
                this@CreateLiveActivity.oAuthData.updateData(oauthData)
            }
        })

        InstanceManager.getLanguageList(this,oAuthData.baseUrl!!, object : InstanceManager.InstanceListener {
            override fun onSuccess(args: Bundle?) {
                val map = args?.getSerializable(InstanceManager.EXTRA_DATA)!! as Map<String, String>
                languages = HashMap(map.count())
                for(pair in map.entries) {
                    val stringId = TranslationUtils.getLanguageTranslationFor(pair.key)
                    if(stringId != -1)
                        languages[getString(stringId)] = pair.value
                    else
                        languages[pair.key] = pair.value
                }
                updateView(null)
            }

            override fun onError(error: String?) {
                inError = true
                updateView(error)
            }

            override fun onUpdateOAuthData(oauthData: OAuthData) {
                this@CreateLiveActivity.oAuthData.updateData(oauthData)
            }
        })
    }

    private fun updateView(error: String?) {
        if(!inError) {
            if (this::configData.isInitialized && !configData.liveEnabled) {
                runOnUiThread {
                    binding.loadingProgress.visibility = View.GONE
                    binding.loadingChannels.visibility = View.GONE
                    binding.liveDisabled.visibility = View.VISIBLE
                }
                return
            }
            if(this::configData.isInitialized && configData.liveEnabled && this::channels.isInitialized && this::categories.isInitialized
                && this::privacies.isInitialized && this::languages.isInitialized && this::licences.isInitialized) {
                val channelAdapter = ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item)
                for (channel in channels) {
                    channelAdapter.add(channel.name)
                }

                val categoryAdapter = ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item)
                val categoryList = ArrayList(categories.keys)
                categoryList.sort()
                categoryAdapter.addAll(categoryList)

                val licencesAdapter = ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item)
                licencesAdapter.addAll(licences.keys)
                licencesAdapter.sort { o1, o2 ->  licences[o1]!!.compareTo(licences[o2]!!)}

                val privacyAdapter = ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item)
                privacyAdapter.addAll(privacies.keys)
                privacyAdapter.sort { o1, o2 ->  privacies[o1]!!.compareTo(privacies[o2]!!)}


                val languageAdapter = ArrayAdapter<String>(this, android.R.layout.simple_spinner_dropdown_item)
                val languageList = ArrayList(languages.keys)
                languageList.sort()
                languageAdapter.addAll(languageList)

                runOnUiThread {
                    binding.goLive.isEnabled = true
                    binding.channelList.adapter = channelAdapter
                    binding.categoryList.adapter = categoryAdapter
                    binding.privacyList.adapter = privacyAdapter
                    binding.licenceList.adapter = licencesAdapter
                    binding.languageList.adapter = languageAdapter
                    binding.loadingProgress.visibility = View.GONE
                    binding.loadingChannels.visibility = View.GONE
                    binding.channelList.visibility = View.VISIBLE
                    binding.liveTitle.visibility = View.VISIBLE
                    binding.channel.visibility = View.VISIBLE
                    binding.title.visibility = View.VISIBLE
                    binding.advanceSettings.visibility = View.VISIBLE
                    binding.privacy.visibility = View.VISIBLE
                    binding.privacyList.visibility = View.VISIBLE
                    if (configData.saveReplayEnabled) {
                        binding.saveReplayLayout.visibility = View.VISIBLE
                        binding.saveReplayInfo.visibility = View.VISIBLE
                    }
                    binding.resolution.visibility = View.VISIBLE
                    binding.resolutionList.visibility = View.VISIBLE
                    restoreSettings()
                }
            }
        } else {
            runOnUiThread {
                binding.error.text = error
                binding.error.visibility = View.VISIBLE
                binding.loadingProgress.visibility = View.GONE
                binding.loadingChannels.visibility = View.GONE
            }
        }
    }

    private fun goLive(streamSettings: StreamSettings) {
        val builder = AlertDialog.Builder(this)
        builder.setCancelable(false)
        builder.setTitle(R.string.creating)
        builder.setView(ProgressBar(this))
        val dialog = builder.show()
        InstanceManager.createLive(this,oAuthData.baseUrl!!,oAuthData,streamSettings,object : InstanceManager.InstanceListener {
            override fun onSuccess(args: Bundle?) {
                if(args != null) {
                    val urlKey = args.getParcelable<StreamData>(InstanceManager.EXTRA_DATA)!!
                    val intent = Intent(this@CreateLiveActivity, StreamActivity::class.java)
                    val streamData = StreamData(urlKey.url,urlKey.key,streamSettings.resolution)
                    intent.putExtra(InstanceManager.EXTRA_DATA,streamData)
                    dialog.dismiss()
                    startLive.launch(intent)
                }
            }

            override fun onError(error: String?) {
                runOnUiThread {
                    binding.error.text = error
                    binding.error.visibility = View.VISIBLE
                    dialog.dismiss()
                }
            }

            override fun onUpdateOAuthData(oauthData: OAuthData) {

            }

        })
    }

    private fun toggleAdvanceSettings() {
        showAdvancedSettings = !showAdvancedSettings
        var status = View.VISIBLE
        binding.advanceSettings.setText(R.string.advanced_settings_expand)
        if (!showAdvancedSettings) {
            status = View.GONE
            binding.advanceSettings.setText(R.string.advanced_settings)
        }


        binding.category.visibility = status
        binding.categoryList.visibility = status
        binding.licence.visibility = status
        binding.licenceList.visibility = status
        binding.language.visibility = status
        binding.languageList.visibility = status
        binding.description.visibility = status
        binding.descriptionTitle.visibility = status
        binding.commentsEnabled.visibility = status
        binding.commentsEnabledTitle.visibility = status
        binding.downloadEnabled.visibility = status
        binding.downloadEnabledTitle.visibility = status
        binding.nsfw.visibility = status
        binding.nsfwTitle.visibility = status
    }

    private fun restoreSettings() {
        val settings = DatabaseManager.getStreamSettings(this)
        if (settings != null) {
            binding.commentsEnabled.isChecked = settings.comments
            binding.downloadEnabled.isChecked = settings.download
            binding.nsfw.isChecked = settings.nsfw
            if (settings.saveReplay != null)
                binding.saveReplay.isChecked = settings.saveReplay
            binding.liveTitle.setText(settings.title)

            if (settings.privacy != 0) {
                for (privacyIdx in 0..privacies.count()) {
                    val privacy = binding.privacyList.getItemAtPosition(privacyIdx)
                    if (privacies[privacy] == settings.privacy) {
                        binding.privacyList.setSelection(privacyIdx)
                        break
                    }
                }
            }
            binding.privacyList.setSelection(settings.privacy -1)

            if (settings.licence != 0 && settings.licence != null) {
                for (licenceIdx in 0..licences.count()) {
                    val licence = binding.licenceList.getItemAtPosition(licenceIdx)
                    if (licences[licence] == settings.licence) {
                        binding.licenceList.setSelection(licenceIdx)
                        break
                    }
                }
            }

            if(settings.category != 0) {
                for (categoryIdx in 0..categories.count()) {
                    val category = binding.categoryList.getItemAtPosition(categoryIdx)
                    if (categories[category] == settings.category) {
                        binding.categoryList.setSelection(categoryIdx)
                        break
                    }
                }
            }
            if (settings.language != null) {
                for (languageIdx in 0..languages.count()) {
                    val language = binding.languageList.getItemAtPosition(languageIdx)
                    if (languages[language].equals(settings.language)) {
                        binding.languageList.setSelection(languageIdx)
                        break
                    }
                }
            }

            binding.resolutionList.setSelection(settings.resolution.ordinal)
        }
    }

    override fun onBackPressed() {
        setResult(-1)
        finish()
        super.onBackPressed()
    }

}