package ctbrec.ui.sites.stripchat;

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 javafx.concurrent.Task;
import okhttp3.HttpUrl;
import okhttp3.Request;
import org.json.JSONArray;
import org.json.JSONObject;

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

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

public class StripchatFollowedUpdateService extends AbstractStripchatUpdateService {
    private static final int PAGE_SIZE = 30;
    private static final String FAVORITES = "/favorites";
    private final Stripchat stripchat;

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

    @Override
    protected Task<List<Model>> createTask() {
        return new Task<>() {
            @Override
            public List<Model> call() throws IOException {
                return loadModels();
            }
        };
    }

    private List<Model> loadModels() 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 (var 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<>();
        var urlBuilder = HttpUrl.parse(stripchat.getBaseUrl() + "/api/front/models/list").newBuilder();
        for (var i = 0; i < modelIdsToLoad.size(); i++) {
            urlBuilder.addQueryParameter("modelIds[" + i + "]", modelIdsToLoad.get(i).toString());
        }
        var 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 (var response = stripchat.getHttpClient().execute(request)) {
            if (response.isSuccessful()) {
                var json = new JSONObject(response.body().string());
                if (json.has("models")) {
                    var users = json.getJSONArray("models");
                    for (var i = 0; i < users.length(); i++) {
                        var user = users.getJSONObject(i);
                        StripchatModel model = stripchat.createModel(user.optString("username"));
                        model.setDescription(user.optString("description"));
                        model.setPreview(getPreviewUrl(user));
                        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;
        var 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 (var response = stripchat.getHttpClient().execute(request)) {
            if (response.isSuccessful()) {
                var json = new JSONObject(response.body().string());
                if (json.has("modelIds")) {
                    var 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) {
        return switch (status) {
            case "public" -> ONLINE;
            case "idle" -> AWAY;
            case "off" -> OFFLINE;
            default -> UNKNOWN;
        };
    }
}
