package ru.yandex.webmaster3.worker.addurl;

import com.google.common.collect.Lists;
import lombok.Builder;
import lombok.Getter;
import org.apache.commons.io.IOUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.tuple.Pair;
import org.jetbrains.annotations.NotNull;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import ru.yandex.webmaster3.core.addurl.UrlForRecrawl;
import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.storage.util.yt.YtRowMapper;
import ru.yandex.wmtools.common.util.http.YandexHttpStatus;

import java.io.InputStream;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author aherman
 */
@Getter
@Builder
public class RecrawlResult implements Comparable<RecrawlResult> {
    private static final Logger log = LoggerFactory.getLogger(RecrawlResult.class);

    private final WebmasterHostId hostId;
    // TODO: когда полностью перейдем на Самовар, relativeUrl будет не нужен
    private final String relativeUrl;
    private final String fullUrl;
    private final DateTime processingTime;
    private final YandexHttpStatus code;
    private final boolean success;

    public RecrawlResult(WebmasterHostId hostId, String relativeUrl, DateTime processingTime,
                         YandexHttpStatus code, boolean success) {
        this.hostId = hostId;
        this.relativeUrl = relativeUrl;
        this.fullUrl = null;
        this.processingTime = processingTime;
        this.code = code;
        this.success = success;
    }

    public RecrawlResult(WebmasterHostId hostId, String relativeUrl, String fullUrl,
                         DateTime processingTime, YandexHttpStatus code, boolean success) {
        this.hostId = hostId;
        this.relativeUrl = relativeUrl;
        this.fullUrl = fullUrl;
        this.processingTime = processingTime;
        this.code = code;
        this.success = success;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }

        RecrawlResult that = (RecrawlResult) o;

        if (hostId != null ? !hostId.equals(that.hostId) : that.hostId != null) {
            return false;
        }
        if (relativeUrl != null ? !relativeUrl.equals(that.relativeUrl) : that.relativeUrl != null) {
            return false;
        }
        return processingTime != null ? processingTime.equals(that.processingTime) : that.processingTime == null;

    }

    @Override
    public int hashCode() {
        int result = hostId != null ? hostId.hashCode() : 0;
        result = 31 * result + (relativeUrl != null ? relativeUrl.hashCode() : 0);
        result = 31 * result + (processingTime != null ? processingTime.hashCode() : 0);
        return result;
    }

    @Override
    public int compareTo(@NotNull RecrawlResult o) {
        return processingTime.compareTo(o.processingTime);
    }

    public static RecrawlResult latest(RecrawlResult r1, RecrawlResult r2) {
        return ObjectUtils.max(r1, r2);
    }

    public static class YtResultRowMapper implements YtRowMapper<RecrawlResult> {

        private static List<String> COLUMNS = Lists.newArrayList("url", "ts", "code", "success");

        private boolean error = false;
        private WebmasterHostId hostId;
        private String relativeUrl;
        private DateTime processingTime;
        private YandexHttpStatus code;
        private boolean success;

        @Override
        public void nextField(String name, InputStream data) {
            try {
                String dataStr = IOUtils.toString(data, StandardCharsets.UTF_8);
                switch (name) {
                    case "url":
                        Pair<WebmasterHostId, String> p = UrlForRecrawl.toHostIdAndRelativeUrl(dataStr);
                        hostId = p.getLeft();
                        relativeUrl = p.getRight();
                        break;
                    case "ts":
                        processingTime = new DateTime(TimeUnit.SECONDS.toMillis(Long.parseLong(dataStr)));
                        break;
                    case "code":
                        code = YandexHttpStatus.parseCode(Integer.parseInt(dataStr));
                        break;
                    case "success":
                        success = Boolean.parseBoolean(dataStr);
                        break;
                    default:
                        throw new IllegalArgumentException("Unknown field " + name);
                }
            } catch (Exception e) {
                log.error("Unable to read Yt result field: {}", name, e);
                error = true;
            }
        }

        @Override
        public RecrawlResult rowEnd() {
            if (error) {
                error = false;
                return null;
            }
            return new RecrawlResult(hostId, relativeUrl, processingTime, code, success);
        }

        @Override
        public List<String> getColumns() {
            return COLUMNS;
        }
    }
}
