package ru.yandex.webmaster3.storage.mobile;

import NCrawl.Feeds;
import com.google.common.util.concurrent.RateLimiter;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.joda.time.Duration;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.http.WebmasterErrorResponse;
import ru.yandex.webmaster3.core.logbroker.writer.LogbrokerClient;
import ru.yandex.webmaster3.core.util.IdUtils;
import ru.yandex.webmaster3.core.util.RetryUtils;
import ru.yandex.webmaster3.core.util.UrlUtils;
import ru.yandex.webmaster3.core.worker.client.WorkerClient;
import ru.yandex.webmaster3.core.worker.task.HostMobileAuditTaskData;
import ru.yandex.webmaster3.storage.mobile.dao.HostMobileAuditQueueYDao;

import java.util.ArrayList;
import java.util.List;
import java.util.function.Consumer;

/**
 * @author leonidrom
 */
@Service
@Slf4j
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class HostMobileAuditService {
    // WMC-9710: сейчас суммарный  RPS проверок на мобилопригодность не должен привышать 2 RPS
    private static final RateLimiter RATE_LIMITER = RateLimiter.create( Math.floor(2d/WorkerClient.TOTAL_WORKERS*10)/10);
    private static final RetryUtils.RetryPolicy LB_WRITE_RETRY_POLICY = RetryUtils.linearBackoff(5, Duration.standardSeconds(30));
    private static final String FEED_NAME = "mobile-check-ext";

    private final LogbrokerClient samovarFeedsExtLogbrokerClient;
    private final HostMobileAuditQueueYDao hostMobileAuditQueueYDao;
    private final WorkerClient workerClient;

    public void requestHostMobileAudit(WebmasterHostId hostId) {
        String hostUrl = IdUtils.hostIdToUrl(hostId);
        String canonizedUrl = UrlUtils.canonizeUrlForRobot(hostUrl);
        if (canonizedUrl == null) {
            log.error("Failed to canonize url: {}", hostUrl);
            canonizedUrl = hostUrl;
        }

        log.info("Sending {} to Samovar", canonizedUrl);

        byte[] data = Feeds.TFeedExt.newBuilder()
                .setFeedName(FEED_NAME)
                .setUrl(canonizedUrl)
                .build()
                .toByteArray();

        try {
            RATE_LIMITER.acquire();
            RetryUtils.execute(LB_WRITE_RETRY_POLICY, () -> samovarFeedsExtLogbrokerClient.write(data));
        } catch (Exception e) {
            throw new WebmasterException("Unable to send request to Logbroker",
                    new WebmasterErrorResponse.LogbrokerErrorResponse(this.getClass(), e));
        }
    }

    public void recheck(WebmasterHostId hostId) {
        hostMobileAuditQueueYDao.addHost(hostId);
        workerClient.enqueueTask(new HostMobileAuditTaskData(hostId));
    }

    public void resendBatch(List<HostMobileAuditQueueYDao.Record> batch) {
        List<HostMobileAuditTaskData> taskBatch = new ArrayList<>();
        for (var r : batch) {
            taskBatch.add(new HostMobileAuditTaskData(r.getHostId()));
            hostMobileAuditQueueYDao.updateResendDate(r.getHostId(), r.getRetriesCount() + 1);
        }

        workerClient.enqueueBatch(taskBatch);
    }

    public void forEachPendingRequest(Consumer<HostMobileAuditQueueYDao.Record> consumer) {
        hostMobileAuditQueueYDao.forEachRequest(consumer);
    }
}
