package de.sebse.fuplanner.services.kvv.sync;

import android.content.Context;

import java.util.HashMap;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import androidx.annotation.Nullable;
import de.sebse.fuplanner.R;
import de.sebse.fuplanner.tools.Preferences;
import de.sebse.fuplanner.tools.network.HTTPService;
import de.sebse.fuplanner.tools.network.NetworkCallback;
import de.sebse.fuplanner.tools.network.NetworkError;
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;

public class FULogin extends HTTPService {
    public FULogin(Context context) {
        super(context);
    }

    public void fulogin(String requestURI, String username, String password, final NetworkCallback<String> callback, final NetworkErrorCallback errorCallback) {
        String old_shib_idp_session = Preferences.getString(getContext(), R.string.pref_shib_idp_session);
        step2(requestURI, old_shib_idp_session, success2 -> {
            String samlResp = success2.get("SAMLResponse");
            if (samlResp != null) {
                callback.onResponse(samlResp);
                return;
            }
            String fuJSESSIONID = success2.get("JSESSIONID");
            step3(fuJSESSIONID, success3 -> {
                step4(username, password, fuJSESSIONID, success4 -> {
                    String shib_idp_session = success4.get("shib_idp_session");
                    Preferences.setString(getContext(), R.string.pref_shib_idp_session, shib_idp_session);
                    String samlResponse = success4.get("SAMLResponse");
                    if (samlResponse != null)
                        callback.onResponse(samlResponse);
                    else
                        errorCallback.onError(new NetworkError(100300, -1, "Cannot get SAML Response!"));
                }, errorCallback);
            }, errorCallback);
        }, errorCallback);
    }

    /*
     2= GET [Location-Header 1]
        -> Set-Cookie: JSESSIONID=[JSESSION-FU]
        -> Location: /idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1
    */
    private void step2(String url, @Nullable String shib_idp_session, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
        HashMap<String, String> cookiesReq = null;
        if (shib_idp_session != null) {
            cookiesReq = new HashMap<>();
            cookiesReq.put("shib_idp_session", shib_idp_session);
        }
        get(url, cookiesReq, response -> {
            String body = response.getParsed();
            if (body != null) {
                Pattern pattern = Pattern.compile("name=\"SAMLResponse\" value=\"([0-9a-zA-Z+]+=*)");
                Matcher matcher = pattern.matcher(body);
                if (!matcher.find()) {
                    errorCallback.onError(new NetworkError(100344, -1, "Error on getting SAML response!"));
                    return;
                }
                HashMap<String, String> object = new HashMap<>();
                object.put("SAMLResponse", matcher.group(1));
                callback.onResponse(object);
                return;
            }
            String cookies = response.getHeaders().get("Set-Cookie");
            if (cookies == null) {
                errorCallback.onError(new NetworkError(100321, -1, "Error on starting FU session!"));
                return;
            }
            HashMap<String, String> object;
            try {
                object = getCookie(cookies, new String[]{"JSESSIONID"});
            } catch (NoSuchFieldException e) {
                errorCallback.onError(new NetworkError(100322, -1, "Error on starting FU session!"));
                return;
            }
            callback.onResponse(object);
        }, error -> errorCallback.onError(new NetworkError(100320, error.networkResponse.statusCode, "Error on starting FU session!")));
    }

    /*
     3= GET [Location-Header 2]
        + Cookie: JSESSIONID=[JSESSION-FU]
     */
    private void step3(String JSESSIONID_FU, final NetworkCallback<Boolean> callback, final NetworkErrorCallback errorCallback) {
        HashMap<String, String> cookies = new HashMap<>();
        cookies.put("JSESSIONID", JSESSIONID_FU);
        head("https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1", cookies, response -> {
            callback.onResponse(true);
        }, error -> errorCallback.onError(new NetworkError(100330, error.networkResponse.statusCode, "Error starting login page!")));
    }

    /*
     4= POST [Location-Header 2]
        + Body: j_username=[USERNAME]&j_password=[PASSWORD]&_eventId_proceed=
        + Header: Content-Type: application/x-www-form-urlencoded
        + Header: Referer: [Location-Header 2]
        + Cookie: JSESSIONID=[JSESSION-FU]
        -> Set-Cookie: shib_idp_session=[SHIB-IDP-SESSION]
        -> Body SAMLResponse-Input-value
     */
    private void step4(String username, String password, String JSESSIONID_FU, final NetworkCallback<HashMap<String, String>> callback, final NetworkErrorCallback errorCallback) {
        HashMap<String, String> cookies = new HashMap<>();
        cookies.put("JSESSIONID", JSESSIONID_FU);
        HashMap<String, String> body = new HashMap<>();
        body.put("j_username", username);
        body.put("j_password", password);
        body.put("_eventId_proceed", "");
        post("https://identity.fu-berlin.de/idp-fub/profile/SAML2/Redirect/SSO?execution=e1s1", cookies, body, response -> {
            String content = response.getParsed();
            if (content == null) {
                errorCallback.onError(new NetworkError(100343, -1, "Error on getting SAML response!"));
                return;
            }

            String cookies1 = response.getHeaders().get("Set-Cookie");
            if (cookies1 ==null) {
                errorCallback.onError(new NetworkError(100341, -1, "Error on logging in to FU Identity Server!"));
                return;
            }
            HashMap<String, String> object;
            try {
                object = getCookie(cookies1, new String[]{"shib_idp_session"});
            } catch (NoSuchFieldException e) {
                errorCallback.onError(new NetworkError(100342, -1, "Error on logging in to FU Identity Server!"));
                return;
            }
            Pattern pattern = Pattern.compile("name=\"SAMLResponse\" value=\"([0-9a-zA-Z+]+=*)");
            Matcher matcher = pattern.matcher(content);
            if (!matcher.find()) {
                errorCallback.onError(new NetworkError(100344, -1, "Error on getting SAML response!"));
                return;
            }
            object.put("SAMLResponse", matcher.group(1));
            callback.onResponse(object);
        }, error -> errorCallback.onError(new NetworkError(100345, error.networkResponse.statusCode, "Error on logging in to FU Identity Server!")));
    }
}
