package it.integry.integrywmsnative.gest.login.viewmodel;

import com.annimon.stream.Stream;

import java.net.MalformedURLException;
import java.net.URL;
import java.util.List;

import javax.inject.Inject;

import it.integry.integrywmsnative.core.interfaces.viewmodel_listeners.ILoadingListener;
import it.integry.integrywmsnative.core.rest.consumers.SystemRESTConsumer;
import it.integry.integrywmsnative.core.settings.SettingsManager;
import it.integry.integrywmsnative.core.utility.UtilityServer;
import it.integry.integrywmsnative.core.utility.UtilityString;
import it.integry.integrywmsnative.gest.login.exception.InvalidServerCodAziendaException;
import it.integry.integrywmsnative.gest.login.exception.InvalidUserDepositException;
import it.integry.integrywmsnative.gest.login.rest.LoginRESTConsumer;

public class LoginViewModel {


    private final SystemRESTConsumer mSystemRESTConsumer;
    private final LoginRESTConsumer mLoginRESTConsumer;

    private Listener mListener;

    @Inject
    public LoginViewModel(SystemRESTConsumer systemRESTConsumer, LoginRESTConsumer loginRESTConsumer) {
        this.mSystemRESTConsumer = systemRESTConsumer;
        this.mLoginRESTConsumer = loginRESTConsumer;
    }


    public void login(String codAzienda, String username, String password) {
        this.sendOnLoadingStarted();

        mLoginRESTConsumer.retrieveServerData(codAzienda, value -> {

            final String serverEndpoint = value.getEndpointRestApi();

            URL u;
            try {
                u = new URL(serverEndpoint);
            } catch (final MalformedURLException e) {
                e.printStackTrace();
                this.sendError(e);
                return;
            }

            final String host = u.getHost();
            final int port = u.getPort();

            UtilityServer.isEmsApiAvailable(host, port, () -> {

                    mLoginRESTConsumer.authenticate(host, port, username, password, loginDTO -> {

                        SettingsManager.i().createUserSession();
                        SettingsManager.i().getUser().setFullname(!UtilityString.isNullOrEmpty(loginDTO.getFull_name()) ? loginDTO.getFull_name() : username);

                        List<String> availableProfiles = null;
                        if(loginDTO.getAvailableProfiles() != null && !loginDTO.getAvailableProfiles().isEmpty()) {
                            availableProfiles = Stream.of(loginDTO.getAvailableProfiles())
                                    .sorted()
                                    .toList();
                        }

                        this.sendOnLoginCompleted(host, port, loginDTO.getFull_name(), availableProfiles);
                    }, this::sendError);


                }, this::sendError);
        }, ex -> {
            this.sendError(new InvalidServerCodAziendaException(codAzienda, ex));
        });
    }


    public void loadDepo(String codAzienda, String host, int port, String username, String password, Runnable onComplete) {

        SettingsManager.i().getServer().setCodAzienda(codAzienda);
        SettingsManager.i().getServer().setHost(host);
        SettingsManager.i().getServer().setPort(port);

        SettingsManager.i().getUser().setUsername(username);
        SettingsManager.i().getUser().setPassword(password);

        this.mSystemRESTConsumer.getAvailableCodMdeps(availableCodMdeps -> {
            SettingsManager.iDB().setAvailableCodMdep(availableCodMdeps);

            if (availableCodMdeps == null || availableCodMdeps.size() == 0) {
                this.sendError(new InvalidUserDepositException());
                return;
            }

            SettingsManager.i().getUserSession().setDepo(availableCodMdeps.get(0));


            if (onComplete != null) onComplete.run();
        }, this::sendError);
    }


    private void sendOnLoadingStarted() {
        if (this.mListener != null) mListener.onLoadingStarted();
    }

    private void sendOnLoadingEnded() {
        if (this.mListener != null) mListener.onLoadingEnded();
    }

    private void sendOnLoginCompleted(String host, int port, String fullName, List<String> availableProfiles) {
        if (this.mListener != null)
            mListener.onLoginCompleted(host, port, fullName, availableProfiles);
    }

    private void sendError(Exception ex) {
        if (this.mListener != null) mListener.onError(ex);
    }

    public LoginViewModel setListener(Listener listener) {
        this.mListener = listener;
        return this;
    }

    public interface Listener extends ILoadingListener {
        void onError(Exception ex);

        void onLoginCompleted(String host, int port, String fullName, List<String> availableProfiles);
    }

}
