package ctbrec.sites.showup;

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

import java.io.IOException;
import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.time.Duration;
import java.time.Instant;
import java.util.ArrayList;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.json.JSONArray;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import ctbrec.Config;
import ctbrec.Model;
import ctbrec.io.HttpClient;
import ctbrec.io.HttpException;
import ctbrec.sites.AbstractSite;
import okhttp3.Request;
import okhttp3.Response;

public class Showup extends AbstractSite {

    private static final Logger LOG = LoggerFactory.getLogger(Showup.class);
    public static final String BASE_URL = "https://showup.tv";

    private ShowupHttpClient httpClient;
    private Instant lastModelListUpdate = Instant.EPOCH;
    private List<Model> models = new ArrayList<>();

    @Override
    public String getName() {
        return "Showup.tv";
    }

    @Override
    public String getBaseUrl() {
        return BASE_URL;
    }

    @Override
    public String getAffiliateLink() {
        return getBaseUrl();
    }

    @Override
    public Model createModel(String name) {
        //        try {
        //            for (Model m : getModelList()) {
        //                if (Objects.equal(m.getName(), name)) {
        //                    return m;
        //                }
        //            }
        //        } catch (IOException e) {
        //            throw new ModelNotFoundException(name, e);
        //        }
        //        throw new ModelNotFoundException(name);
        ShowupModel model = new ShowupModel();
        model.setSite(this);
        model.setName(name);
        model.setUrl(BASE_URL + '/' + URLEncoder.encode(name, StandardCharsets.UTF_8));
        return model;
    }

    public List<Model> getModelList() throws IOException {
        if(Duration.between(lastModelListUpdate, Instant.now()).getSeconds() > 10) {
            lastModelListUpdate = Instant.now();
            String url = getBaseUrl() + "/site/get_stream_list/big";
            Request req = new Request.Builder()
                    .url(url)
                    .header(USER_AGENT, Config.getInstance().getSettings().httpUserAgent)
                    .build();

            try (Response response = getHttpClient().execute(req)) {
                if (response.isSuccessful()) {
                    String body = response.body().string();
                    LOG.trace(body);
                    JSONObject json = new JSONObject(body);
                    models = new ArrayList<>();
                    JSONArray list = json.getJSONArray("list");
                    for (int i = 0; i < list.length(); i++) {
                        JSONObject entry = list.getJSONObject(i);
                        ShowupModel model = new ShowupModel();
                        model.setPreview(getBaseUrl() + "/files/" + entry.optString("small_img") + ".jpg");
                        model.setDescription(entry.optString("description"));
                        model.setName(entry.optString("username"));
                        model.setUrl(getBaseUrl() + '/' + model.getName());
                        // TODO figure what these flags mean, because you can still stream the models, if is_prv or is_group is set ?!?
                        //                    if(entry.optInt("is_group") == 1) {
                        //                        model.setOnlineState(GROUP);
                        //                    } else if(entry.optInt("is_prv") == 1) {
                        //                        model.setOnlineState(PRIVATE);
                        //                    } else {
                        //                        model.setOnlineState(ONLINE);
                        //                    }
                        model.setOnlineState(ONLINE);
                        model.setStreamId(entry.optString("stream_id"));
                        model.setStreamTranscoderAddr(entry.optString("stream_transcoder_addr"));
                        model.setSite(this);
                        models.add(model);
                    }
                } else {
                    throw new HttpException(response.code(), response.message());
                }
            }
        }
        return models;
    }

    @Override
    public Double getTokenBalance() throws IOException {
        return 0d;
    }

    @Override
    public String getBuyTokensLink() {
        return getBaseUrl();
    }

    @Override
    public boolean login() throws IOException {
        return getHttpClient().login();
    }

    @Override
    public HttpClient getHttpClient() {
        if (httpClient == null) {
            httpClient = new ShowupHttpClient();
        }
        return httpClient;
    }

    @Override
    public void init() throws IOException {
        // noop
    }

    @Override
    public void shutdown() {
        if (httpClient != null) {
            httpClient.shutdown();
        }
    }

    @Override
    public boolean supportsTips() {
        return false;
    }

    @Override
    public boolean supportsFollow() {
        return false;
    }

    @Override
    public boolean isSiteForModel(Model m) {
        return m instanceof ShowupModel;
    }

    @Override
    public boolean credentialsAvailable() {
        return false;
    }

    @Override
    public Model createModelFromUrl(String url) {
        Matcher matcher = Pattern.compile("https?://(?:.*?\\.)?showup.tv(?:/profile)?/(.*)").matcher(url);
        if (matcher.find()) {
            return createModel(matcher.group(1));
        } else {
            return super.createModelFromUrl(url);
        }
    }

}
