package de.sebse.fuplanner.services.kvv;

import android.content.Context;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.io.IOException;
import java.util.ArrayList;
import java.util.LinkedHashSet;

import de.sebse.fuplanner.services.kvv.types.Lecturer;
import de.sebse.fuplanner.services.kvv.types.LecturerStorage;
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;

class ModulesListLecturer extends HTTPService {
    private final Login mLogin;
    private final LecturerStorage mStorage;

    public ModulesListLecturer(Context context, Login login) {
        super(context);
        this.mLogin = login;
        LecturerStorage storage = null;
        try {
            storage = LecturerStorage.load(context);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        if (storage == null) {
            mStorage = new LecturerStorage();
        } else {
            mStorage = storage;
        }
    }

    public void getBBLecturers(String moduleID, NetworkCallback<LinkedHashSet<Lecturer>> callback, NetworkErrorCallback errorCallback) {
        ArrayList<String> lecturerString = mStorage.getLecturersPerCourse(moduleID);
        if (lecturerString != null) {
            final int[] latch = {lecturerString.size()};
            LinkedHashSet<Lecturer> lecturers = new LinkedHashSet<>();
            for (String userId : lecturerString) {
                getBBLecturer(userId, success -> {
                    lecturers.add(success);
                    if (--latch[0] == 0) callback.onResponse(lecturers);
                }, error -> {
                    log.e(error);
                    if (--latch[0] == 0) callback.onResponse(lecturers);
                });
            }
            return;
        }

        if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenBB() == null || !mLogin.getLoginTokenBB().isAvailable()) {
            errorCallback.onError(new NetworkError(102100, 500, "Currently running in offline mode!"));
            return;
        }

        get(String.format("https://lms.fu-berlin.de/learn/api/public/v1/courses/%s/users?fields=userId,courseRoleId", moduleID), mLogin.getLoginTokenBB().getCookies(), response -> {
            String body = response.getParsed();
            if (body == null) {
                errorCallback.onError(new NetworkError(102101, 403, "No lecturers retrieved!"));
                return;
            }
            JSONArray sites;
            try {
                JSONObject json = new JSONObject(body);
                sites = json.getJSONArray("results");
            } catch (JSONException e) {
                e.printStackTrace();
                errorCallback.onError(new NetworkError(102102, 403, "Cannot parse lecturers!"));
                return;
            }

            LinkedHashSet<Lecturer> lecturers = new LinkedHashSet<>();
            final int[] latch = {sites.length()};
            ArrayList<String> lecturerString2 = new ArrayList<>();
            NetworkCallback<LinkedHashSet<Lecturer>> successCallback = l -> {
                mStorage.setLecturersPerCourse(moduleID, lecturerString2);
                try {
                    mStorage.save(getContext());
                } catch (IOException e) {
                    e.printStackTrace();
                }
                callback.onResponse(lecturers);
            };
            for (int i = 0; i < sites.length(); i++) {
                try {
                    JSONObject lecturerJson = sites.getJSONObject(i);
                    String userId = lecturerJson.getString("userId");
                    String role = lecturerJson.getString("courseRoleId");
                    if (!"Student".equals(role)) {
                        lecturerString2.add(userId);
                        getBBLecturer(userId, success -> {
                            lecturers.add(success);
                            if (--latch[0] == 0) successCallback.onResponse(lecturers);
                        }, error -> {
                            log.e(error);
                            if (--latch[0] == 0) successCallback.onResponse(lecturers);
                        });
                    } else {
                        if (--latch[0] == 0) successCallback.onResponse(lecturers);
                    }
                } catch (JSONException e) {
                    log.e(new NetworkError(102103, 403, "Cannot parse lecturers!"));
                    log.e("ID:", i, "JSON:", sites);
                    e.printStackTrace();
                    if (--latch[0] == 0) successCallback.onResponse(lecturers);
                }
            }
        }, error -> errorCallback.onError(new NetworkError(102104, error.networkResponse.statusCode, "Error retrieving lecturers!")));
    }

    public void getBBLecturer(String lecturerID, NetworkCallback<Lecturer> callback, NetworkErrorCallback errorCallback) {
        Lecturer lecturerStore = mStorage.getLecturer(lecturerID);
        if (lecturerStore != null) {
            callback.onResponse(lecturerStore);
            return;
        }

        if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenBB() == null || !mLogin.getLoginTokenBB().isAvailable()) {
            errorCallback.onError(new NetworkError(102110, 500, "Currently running in offline mode!"));
            return;
        }
        get(String.format("https://lms.fu-berlin.de/learn/api/public/v1/users/%s?fields=userName,name", lecturerID), mLogin.getLoginTokenBB().getCookies(), response -> {
            String body = response.getParsed();
            if (body == null) {
                errorCallback.onError(new NetworkError(102111, 403, "No lecturer retrieved!"));
                return;
            }
            try {
                JSONObject json = new JSONObject(body);
                String userName = json.getString("userName");
                String givenName = json.getJSONObject("name").getString("given");
                String familyName = json.getJSONObject("name").getString("family");
                Lecturer lecturer = new Lecturer(givenName, familyName, userName + "@zedat.fu-berlin.de", true);
                mStorage.setLecturer(lecturerID, lecturer);
                try {
                    mStorage.save(getContext());
                } catch (IOException e) {
                    e.printStackTrace();
                }
                callback.onResponse(lecturer);
            } catch (JSONException e) {
                e.printStackTrace();
                errorCallback.onError(new NetworkError(102112, 403, "Cannot parse lecturer!"));
                return;
            }
        }, error -> errorCallback.onError(new NetworkError(102113, error.networkResponse.statusCode, "Error retrieving lecturer!")));
    }
}
