/**
 *  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.dialog

import android.app.Dialog
import android.os.Bundle
import android.os.Handler
import android.os.Looper
import android.view.LayoutInflater
import android.view.View
import androidx.appcompat.app.AlertDialog
import androidx.databinding.DataBindingUtil
import androidx.fragment.app.DialogFragment
import fr.mobdev.peertubelive.R
import fr.mobdev.peertubelive.databinding.AddInstanceBinding
import fr.mobdev.peertubelive.manager.DatabaseManager
import fr.mobdev.peertubelive.manager.InstanceManager
import fr.mobdev.peertubelive.objects.OAuthData
import java.net.MalformedURLException
import java.net.URL

class AddInstanceDialog : DialogFragment() {

    private var onAddInstanceListener: OnAddInstanceListener? = null
    private lateinit var oAuthData: OAuthData


    override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
        val binding = DataBindingUtil.inflate<AddInstanceBinding>(LayoutInflater.from(requireContext()), R.layout.add_instance,null,false)

        val builder = AlertDialog.Builder(requireContext())

        builder.setTitle(R.string.add_instance)
        builder.setPositiveButton(R.string.connect, null)
        builder.setNegativeButton(R.string.cancel) { dialog,_ -> dialog.dismiss() }
        builder.setView(binding.root)
        binding.errorUsername.visibility = View.GONE
        binding.errorInstance.visibility = View.GONE
        binding.errorPassword.visibility = View.GONE
        binding.tryConnect.visibility = View.GONE
        binding.tryConnectMsg.visibility = View.GONE

        if (this::oAuthData.isInitialized)
        {
            builder.setTitle(R.string.connection)
            binding.username.isEnabled = false
            binding.instance.isEnabled = false
            binding.instance.setText(oAuthData.baseUrl)
            binding.username.setText(oAuthData.username)
        }


        val dialog = builder.create()
        dialog.setOnShowListener {
            dialog.getButton(AlertDialog.BUTTON_POSITIVE).setOnClickListener {
                val username = binding.username.text.toString()
                val password = binding.password.text.toString()
                var instance = binding.instance.text.toString()
                binding.errorUsername.visibility = View.GONE
                binding.errorInstance.visibility = View.GONE
                binding.errorPassword.visibility = View.GONE
                binding.error.visibility = View.GONE
                var inError = false
                if(username.isEmpty())
                {
                    binding.errorUsername.visibility = View.VISIBLE
                    inError = true
                }
                if(password.isEmpty())
                {
                    binding.errorPassword.visibility = View.VISIBLE
                    inError = true
                }
                if(instance.isEmpty())
                {
                    binding.errorInstance.visibility = View.VISIBLE
                    binding.errorInstance.setText(R.string.instance_error)
                    inError = true
                } else {
                    if(!instance.startsWith("https://"))
                        instance = "https://$instance"
                    if (instance.endsWith("/"))
                        instance = instance.removeRange(instance.length-1,instance.length)
                    try {
                        URL(instance)
                    } catch (e: MalformedURLException) {
                        binding.errorInstance.visibility = View.VISIBLE
                        binding.errorInstance.setText(R.string.malformed_instance_error)
                        inError = true
                    }
                }
                if (!this::oAuthData.isInitialized && DatabaseManager.existsCredential(requireContext(),instance,username)) {
                    inError = true
                    binding.error.visibility = View.VISIBLE
                    binding.error.text = requireContext().getString(R.string.account_exist)
                }
                if(!inError) {
                    binding.errorUsername.visibility = View.GONE
                    binding.errorInstance.visibility = View.GONE
                    binding.errorPassword.visibility = View.GONE
                    binding.error.visibility = View.GONE
                    binding.username.visibility = View.GONE
                    binding.password.visibility = View.GONE
                    binding.instance.visibility = View.GONE
                    binding.usernameTitle.visibility = View.GONE
                    binding.passwordTitle.visibility = View.GONE
                    binding.instanceTitle.visibility = View.GONE
                    binding.tryConnect.visibility = View.VISIBLE
                    binding.tryConnectMsg.visibility = View.VISIBLE

                    dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = false
                    dialog.getButton(AlertDialog.BUTTON_NEGATIVE).isEnabled = false
                    val listener = object : InstanceManager.InstanceListener {
                        override fun onSuccess(args: Bundle?) {
                            val oauthData: OAuthData? = args?.getParcelable(InstanceManager.EXTRA_DATA)
                            if (oauthData != null) {
                                if (this@AddInstanceDialog::oAuthData.isInitialized) {
                                    DatabaseManager.updateCredentials(requireContext(), oauthData)
                                } else {
                                    DatabaseManager.addNewCredentials(requireContext(), oauthData)
                                }
                                onAddInstanceListener?.addSuccess(oauthData)
                                dialog.dismiss()
                            }
                        }

                        override fun onError(error: String?) {
                            Handler(Looper.getMainLooper()).post {
                                binding.error.visibility = View.VISIBLE
                                binding.tryConnect.visibility = View.GONE
                                binding.tryConnectMsg.visibility = View.GONE
                                binding.username.visibility = View.VISIBLE
                                binding.password.visibility = View.VISIBLE
                                binding.instance.visibility = View.VISIBLE
                                binding.usernameTitle.visibility = View.VISIBLE
                                binding.passwordTitle.visibility = View.VISIBLE
                                binding.instanceTitle.visibility = View.VISIBLE
                                binding.error.text = error
                                dialog.getButton(AlertDialog.BUTTON_POSITIVE).isEnabled = true
                                dialog.getButton(AlertDialog.BUTTON_NEGATIVE).isEnabled = true
                            }
                        }

                        override fun onUpdateOAuthData(oauthData: OAuthData) {
                            DatabaseManager.updateCredentials(requireContext(), oauthData)
                        }

                    };
                    if (this::oAuthData.isInitialized) {
                        InstanceManager.getUserToken(requireContext(), instance, username, password, oAuthData, listener)
                    } else {
                        InstanceManager.registerAccount(requireContext(), instance, username, password,listener)
                    }
                }
            }
        }
        return dialog
    }

    fun setOnAddInstanceListener(listener: OnAddInstanceListener) {
        onAddInstanceListener = listener
    }

    fun setOauthData(oAuthData: OAuthData) {
        this.oAuthData = oAuthData
    }

    interface OnAddInstanceListener {
        fun addSuccess(oAuthData: OAuthData)
    }
}