package ctbrec.ui.sites.stripchat;

import static ctbrec.Model.State.*;
import static ctbrec.io.HttpConstants.*;

import java.io.IOException;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

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

import ctbrec.Config;
import ctbrec.Model;
import ctbrec.io.HttpException;
import ctbrec.sites.stripchat.Stripchat;
import ctbrec.sites.stripchat.StripchatHttpClient;
import ctbrec.sites.stripchat.StripchatModel;
import ctbrec.ui.SiteUiFactory;
import ctbrec.ui.tabs.PaginatedScheduledService;
import javafx.concurrent.Task;
import okhttp3.HttpUrl;
import okhttp3.Request;
import okhttp3.Response;

public class StripchatFollowedUpdateService extends PaginatedScheduledService {
    private static final int PAGE_SIZE = 30;
    private Stripchat stripchat;

    public StripchatFollowedUpdateService(Stripchat stripchat) {
        this.stripchat = stripchat;
    }

    @Override
    protected Task<List<Model>> createTask() {
        return new Task<List<Model>>() {
            @Override
            public List<Model> call() throws IOException {
                int startIndex = (getPage() - 1) * PAGE_SIZE;
                JSONArray favoriteModelIds = loadFavoriteModelIds();
                List<Integer> modelIdsToLoad = new ArrayList<>(PAGE_SIZE);
                List<Model> models;
                if (startIndex < favoriteModelIds.length()) {
                    int modelsOnPage = Math.min(PAGE_SIZE, favoriteModelIds.length() - startIndex - 1);
                    for (int i = 0; i < modelsOnPage; i++) {
                        modelIdsToLoad.add(favoriteModelIds.getInt(startIndex + i));
                    }
                    models = loadModels(modelIdsToLoad);
                } else {
                    models = Collections.emptyList();
                }
                return models;
            }

            private List<Model> loadModels(List<Integer> modelIdsToLoad) throws IOException {
                List<Model> models = new ArrayList<>();
                HttpUrl.Builder urlBuilder = HttpUrl.parse(stripchat.getBaseUrl() + "/api/front/models/list").newBuilder();
                for (int i = 0; i < modelIdsToLoad.size(); i++) {
                    urlBuilder.addQueryParameter("modelIds["+i+"]", modelIdsToLoad.get(i).toString());
                }
                Request request = new Request.Builder()
                        .url(urlBuilder.build())
                        .header(ACCEPT, "*/*")
                        .header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
                        .header(REFERER, Stripchat.baseUri + "/favorites")
                        .header(CONTENT_TYPE, MIMETYPE_APPLICATION_JSON)
                        .build();
                try (Response response = stripchat.getHttpClient().execute(request)) {
                    if (response.isSuccessful()) {
                        JSONObject json = new JSONObject(response.body().string());
                        if (json.has("models")) {
                            JSONArray users = json.getJSONArray("models");
                            for (int i = 0; i < users.length(); i++) {
                                JSONObject user = users.getJSONObject(i);
                                StripchatModel model = stripchat.createModel(user.optString("username"));
                                model.setDescription(user.optString("description"));
                                model.setPreview(user.optString("previewUrlThumbBig"));
                                model.setOnlineState(mapStatus(user.optString("status")));
                                models.add(model);
                            }
                        }
                    } else {
                        throw new HttpException(response.code(), response.message());
                    }
                }
                return models;
            }

            private JSONArray loadFavoriteModelIds() throws IOException {
                SiteUiFactory.getUi(stripchat).login();
                stripchat.getHttpClient().login();
                long userId = ((StripchatHttpClient) stripchat.getHttpClient()).getUserId();
                String url = stripchat.getBaseUrl() + "/api/front/users/" + userId + "/favorites";
                Request request = new Request.Builder()
                        .url(url)
                        .header(ACCEPT, MIMETYPE_APPLICATION_JSON)
                        .header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
                        .header(ORIGIN, Stripchat.baseUri)
                        .header(REFERER, Stripchat.baseUri + "/favorites")
                        .header(CONTENT_TYPE, MIMETYPE_APPLICATION_JSON)
                        .build();
                try (Response response = stripchat.getHttpClient().execute(request)) {
                    if (response.isSuccessful()) {
                        JSONObject json = new JSONObject(response.body().string());
                        if (json.has("modelIds")) {
                            JSONArray userIds = json.getJSONArray("modelIds");
                            return userIds;
                        } else {
                            return new JSONArray();
                        }
                    } else {
                        throw new HttpException(response.code(), response.message());
                    }
                }
            }
        };
    }

    protected ctbrec.Model.State mapStatus(String status) {
        switch (status) {
        case "public":
            return ONLINE;
        case "idle":
            return AWAY;
        case "off":
            return OFFLINE;
        default:
            return UNKNOWN;
        }
    }
}
