package ru.yandex.webmaster3.storage.nca;

import java.util.ArrayList;
import java.util.List;

import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Preconditions;
import lombok.RequiredArgsConstructor;
import lombok.Value;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.tuple.Pair;
import org.springframework.stereotype.Service;

import ru.yandex.webmaster3.core.util.json.JsonMapping;
import ru.yandex.webmaster3.core.zora.GoZoraService;
import ru.yandex.webmaster3.core.zora.go_data.request.GoZoraRequest;
import ru.yandex.webmaster3.core.zora.go_data.response.SimpleGoZoraResponse;
import ru.yandex.webmaster3.storage.nca.data.UnparsedEntry;

/**
 * @author kravchenko99
 * @date 4/28/22
 */

@Slf4j
@Service
@RequiredArgsConstructor
public class CertificateTransparencyLogService {

    public static final String HTTPS_PREFIX = "https://";
    public static final String HTTP_PREFIX = "http://";
    private static final String GET_STH_PATH = "ct/v1/get-sth";
    private static final String GET_ENTRIES = "ct/v1/get-entries";

    public static final String YANDEX_CTLOG_INFOS_URL = "https://browser-resources.s3.yandex.net/ctlog/ctlog.json";
    public static final String GOOGLE_CTLOG_INFOS_URL = "https://www.gstatic.com/ct/log_list/log_list.json";

    public final GoZoraService goZoraService;

    public List<Pair<String, String>> getYandexLogs() {
        SimpleGoZoraResponse simpleGoZoraResponse =
                goZoraService.executeRequest(new GoZoraRequest(YANDEX_CTLOG_INFOS_URL,
                        false, false, true));

        Info info = JsonMapping.readValue(simpleGoZoraResponse.getBody(), Info.class);
        List<Pair<String, String>> result = new ArrayList<>();
        for (OperatorInfo operatorInfo : info.getOperators()) {
            for (CtlogInfo logInfo : operatorInfo.getLogs()) {
                String ctlogUrl = logInfo.getUrl();
                // обрезаю чтобы были как гугловые, если захотим их парсить дополнительно
                if (ctlogUrl.startsWith(HTTPS_PREFIX)) {
                    ctlogUrl = ctlogUrl.substring(HTTPS_PREFIX.length());
                } else if (ctlogUrl.startsWith(HTTP_PREFIX)) {
                    ctlogUrl = ctlogUrl.substring(HTTP_PREFIX.length());
                }
                result.add(Pair.of(ctlogUrl, operatorInfo.getName()));
                log.info("Get ctlog with ctlogUrl - {} and description \"{}\"", ctlogUrl, logInfo.getDescription());
            }
        }
        return result;
    }

    public List<String> getGoogleLogs() {
        SimpleGoZoraResponse simpleGoZoraResponse =
                goZoraService.executeRequest(new GoZoraRequest(GOOGLE_CTLOG_INFOS_URL,
                        false, false, true));

        OperatorInfo info = JsonMapping.readValue(simpleGoZoraResponse.getBody(), OperatorInfo.class);
        List<String> result = new ArrayList<>();
        for (CtlogInfo logInfo : info.getLogs()) {
            String ctlogUrl = logInfo.getUrl();
            // обрезаю чтобы были как гугловые, если захотим их парсить дополнительно
            if (ctlogUrl.startsWith(HTTPS_PREFIX)) {
                ctlogUrl = ctlogUrl.substring(HTTPS_PREFIX.length());
            } else if (ctlogUrl.startsWith(HTTP_PREFIX)) {
                ctlogUrl = ctlogUrl.substring(HTTP_PREFIX.length());
            }
            result.add(ctlogUrl);
            log.info("Get ctlog with ctlogUrl - {} and description \"{}\"", ctlogUrl, logInfo.getDescription());
        }
        return result;
    }

    public int getLogSize(String ctlogUrl) {
        String url = HTTPS_PREFIX + ctlogUrl + GET_STH_PATH;
        SimpleGoZoraResponse simpleGoZoraResponse = goZoraService.executeRequest(new GoZoraRequest(url,
                false, false, true));

        return JsonMapping.readTree(simpleGoZoraResponse.getBody()).get("tree_size").asInt();
    }

    public List<UnparsedEntry> getEntries(String ctlogUrl, int start, int end) {
        Preconditions.checkArgument(end - start + 1 < 1000, "Recommendation dont use page size > 1000");
        String url = HTTPS_PREFIX + ctlogUrl + GET_ENTRIES + "?start=" + start + "&end=" + end;
        SimpleGoZoraResponse simpleGoZoraResponse = goZoraService.executeRequest(new GoZoraRequest(url,
                false, false, true));

        return JsonMapping.readValue(simpleGoZoraResponse.getBody(), ListEntries.class).getEntries();
    }


    @Value
    private static class ListEntries {
        @JsonProperty("entries")
        List<UnparsedEntry> entries;
    }

    @Value
    private static class CtlogInfo {
        @JsonProperty("description")
        String description;
        @JsonProperty("url")
        String url;
    }

    @Value
    private static class OperatorInfo {
        @JsonProperty("logs")
        List<CtlogInfo> logs;
        String name;
    }

    @Value
    private static class Info {
        @JsonProperty("operators")
        List<OperatorInfo> operators;
    }
}
