package org.mercury_im.messenger.android.ui.roster.contacts;

import android.app.AlertDialog;
import android.app.Dialog;
import android.content.Context;
import android.content.DialogInterface;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ArrayAdapter;
import android.widget.Button;
import android.widget.LinearLayout;
import android.widget.Spinner;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatDialogFragment;

import com.google.android.material.textfield.TextInputEditText;
import com.google.android.material.textfield.TextInputLayout;

import org.jivesoftware.smack.SmackException;
import org.jxmpp.stringprep.XmppStringprepException;
import org.mercury_im.messenger.core.Messenger;
import org.mercury_im.messenger.R;
import org.mercury_im.messenger.entity.Account;
import org.mercury_im.messenger.core.exception.ContactAlreadyAddedException;

import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;
import io.reactivex.android.schedulers.AndroidSchedulers;
import io.reactivex.disposables.CompositeDisposable;
import io.reactivex.schedulers.Schedulers;

public class AddContactDialogFragment extends AppCompatDialogFragment {

    private final List<Account> accounts;
    private final Messenger messenger;

    @BindView(R.id.account_select_container)
    LinearLayout accountSelectorContainer;

    @BindView(R.id.spinner)
    Spinner accountSelector;

    @BindView(R.id.address_layout)
    TextInputLayout contactAddressLayout;

    @BindView(R.id.address)
    TextInputEditText contactAddress;

    private final CompositeDisposable disposable = new CompositeDisposable();

    public AddContactDialogFragment(List<Account> accountList, Messenger messenger) {
        this.accounts = accountList;
        this.messenger = messenger;
    }

    @NonNull
    @Override
    public Dialog onCreateDialog(@Nullable Bundle savedInstanceState) {
        LayoutInflater inflater = requireActivity().getLayoutInflater();
        View dialogView = inflater.inflate(R.layout.dialog_add_contact, null);
        ButterKnife.bind(this, dialogView);

        AlertDialog.Builder builder = new AlertDialog.Builder(getActivity());

        // Hide Spinner when only one account.
        if (accounts == null || accounts.size() <= 1) {
            accountSelectorContainer.setVisibility(View.GONE);
        }

        accountSelector.setAdapter(new AccountAdapter(requireActivity(), accounts));
        accountSelector.setSelection(0);

        builder.setTitle(R.string.dialog_title_add_contact)
                .setView(dialogView)
                .setCancelable(false)
                .setPositiveButton(R.string.button_add, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        // Later overwrite in onResume.
                    }
                })
                .setNegativeButton(R.string.button_cancel, new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        AddContactDialogFragment.this.onCancel(dialog);
                    }
                });

        return builder.create();
    }

    @Override
    public void onResume()
    {
        super.onResume();
        final AlertDialog d = (AlertDialog)getDialog();
        if(d == null) {
            return;
        }
        Button positiveButton = d.getButton(Dialog.BUTTON_POSITIVE);
        positiveButton.setOnClickListener(v -> {
            Account account = accounts.get(accountSelector.getSelectedItemPosition());
            String address = contactAddress.getText() != null ? contactAddress.getText().toString() : "";
            disposable.add(messenger.addContact(account.getId(), address)
                    .subscribeOn(Schedulers.io())
                    .observeOn(AndroidSchedulers.mainThread())
                    .subscribe(
                            AddContactDialogFragment.this::dismiss,
                            e -> {
                                if (e instanceof SmackException.NotLoggedInException || e instanceof SmackException.NotConnectedException) {
                                    contactAddressLayout.setError(getString(R.string.error_account_not_connected));
                                } else if (e instanceof ContactAlreadyAddedException) {
                                    contactAddressLayout.setError(getString(R.string.error_contact_already_added));
                                } else if (e instanceof XmppStringprepException) {
                                    contactAddressLayout.setError(getString(R.string.error_invalid_address));
                                } else {
                                    contactAddressLayout.setError(e.getClass().getName());
                                }
                            }
                    ));
        });
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        disposable.dispose();
    }

    private static class AccountAdapter extends ArrayAdapter<Account> {

        public AccountAdapter(@NonNull Context context, @NonNull List<Account> objects) {
            super(context, R.layout.spinner_item_account, objects);
        }

        @NonNull
        @Override
        public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
            if (convertView == null) {
                convertView = LayoutInflater.from(getContext()).inflate(R.layout.spinner_item_account, parent, false);
            }
            TextView textView = convertView.findViewById(R.id.account_address);
            textView.setText(getItem(position).getAddress());
            return convertView;
        }

        @Override
        public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
            return getView(position, convertView, parent);
        }
    }
}
