package de.sebse.fuplanner.services.kvv;

import android.content.Context;

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

import java.util.ArrayList;

import de.sebse.fuplanner.services.kvv.types.Announcement;
import de.sebse.fuplanner.services.kvv.types.Modules;
import de.sebse.fuplanner.tools.UtilsDate;
import de.sebse.fuplanner.tools.network.NetworkCallback;
import de.sebse.fuplanner.tools.network.NetworkError;
import de.sebse.fuplanner.tools.network.NetworkErrorCallback;

public class ModulesAnnouncements extends PartModules<ArrayList<Announcement>> {

    ModulesAnnouncements(Login login, ModulesList list, Context context) {
        super(login, list, context);
    }

    @Override
    protected ArrayList<Announcement> getPart(Modules.Module module) {
        return module.announcements;
    }

    @Override
    protected boolean setPart(Modules.Module module, ArrayList<Announcement> part) {
        boolean changed = module.announcements == null || module.announcements.hashCode() != part.hashCode();
        module.announcements = part;
        return changed;
    }

    @Override
    protected void upgradeKVV(final String ID, final NetworkCallback<ArrayList<Announcement>> callback, final NetworkErrorCallback errorCallback) {
        if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenKVV() == null || !mLogin.getLoginTokenKVV().isAvailable()) {
            errorCallback.onError(new NetworkError(101204, 500, "Currently running in offline mode!"));
            return;
        }
        super.get(String.format("https://kvv.imp.fu-berlin.de/direct/announcement/site/%s.json?n=999999&d=999999999", ID), mLogin.getLoginTokenKVV().getCookies(), response -> {
            String body = response.getParsed();
            if (body == null) {
                errorCallback.onError(new NetworkError(101201, 403, "No announcements retrieved!"));
                return;
            }
            ArrayList<Announcement> announcements = new ArrayList<>();
            JSONArray sites;
            try {
                JSONObject json = new JSONObject(body);
                sites = json.getJSONArray("announcement_collection");
            } catch (JSONException e) {
                e.printStackTrace();
                errorCallback.onError(new NetworkError(101202, 403, "Cannot parse announcements!"));
                return;
            }

            for (int i = 0; i < sites.length(); i++) {
                try {
                    JSONObject site = sites.getJSONObject(i);
                    String id = site.getString("announcementId");
                    String title = site.getString("title");
                    String text = site.getString("body");
                    text = String.valueOf(fromHtml(text));
                    String createdBy = site.getString("createdByDisplayName");
                    long createdOn = site.getLong("createdOn");

                    // Extract attachment links
                    JSONArray attachments = site.getJSONArray("attachments");
                    ArrayList<String> urls = new ArrayList<>();
                    for (int j = 0; j < attachments.length(); j++) {
                        urls.add(attachments.getJSONObject(j).optString("url", null));
                    }

                    announcements.add(new Announcement(id, title, text, createdBy, createdOn, urls));
                } catch (JSONException e) {
                    log.e(new NetworkError(101205, 403, "Cannot parse announcements!"));
                    log.e("ID:", i, "JSON:", sites);
                    e.printStackTrace();
                    return;
                }
            }

            // Empty announcements *may be* because token is invalid -> check
            if (announcements.size() == 0)
                mLogin.testLoginToken(token -> callback.onResponse(announcements), errorCallback);
            else
                callback.onResponse(announcements);
        }, error -> errorCallback.onError(new NetworkError(101203, error.networkResponse.statusCode, "Cannot get announcements!")));
    }

    @Override
    protected void upgradeBB(String ID, NetworkCallback<ArrayList<Announcement>> callback, NetworkErrorCallback errorCallback) {
        if (!mLogin.isInOnlineMode() || mLogin.getLoginTokenBB() == null || !mLogin.getLoginTokenBB().isAvailable()) {
            errorCallback.onError(new NetworkError(101214, 500, "Currently running in offline mode!"));
            return;
        }
        super.get(String.format("https://lms.fu-berlin.de/learn/api/v1/courses/%s/announcements?fields=id,title,body.rawText,startDateRestriction,creatorUserId", ID), mLogin.getLoginTokenBB().getCookies(), response -> {
            String body = response.getParsed();
            if (body == null) {
                errorCallback.onError(new NetworkError(101211, 403, "No announcements retrieved!"));
                return;
            }
            ArrayList<Announcement> announcements = new ArrayList<>();
            JSONArray sites;
            try {
                JSONObject json = new JSONObject(body);
                sites = json.getJSONArray("results");
            } catch (JSONException e) {
                e.printStackTrace();
                errorCallback.onError(new NetworkError(101212, 403, "Cannot parse announcements!"));
                return;
            }

            for (int i = 0; i < sites.length(); i++) {
                try {
                    JSONObject site = sites.getJSONObject(i);
                    String id = site.getString("id");
                    String title = site.getString("title");
                    String text = site.getJSONObject("body").getString("rawText");
                    text = String.valueOf(fromHtml(text));
                    String createdBy = "";//site.getStringArray("createdByDisplayName");
                    long createdOn = UtilsDate.stringToMillis(site.getString("startDateRestriction"), "yyyy-MM-dd'T'HH:mm:ss.SSS'Z'");
                    ArrayList<String> urls = new ArrayList<>();

                    announcements.add(new Announcement(id, title, text, createdBy, createdOn, urls));
                } catch (JSONException e) {
                    log.e(new NetworkError(101215, 403, "Cannot parse announcements!"));
                    log.e("ID:", i, "JSON:", sites);
                    e.printStackTrace();
                    return;
                }
            }

            callback.onResponse(announcements);
        }, error -> errorCallback.onError(new NetworkError(101213, error.networkResponse.statusCode, "Cannot get announcements!")));
    }
}
