package ru.yandex.webmaster3.storage.url.checker2;

import com.datastax.driver.core.utils.UUIDs;
import lombok.RequiredArgsConstructor;
import org.joda.time.DateTime;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
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.storage.url.checker2.dao.UrlCheckRequestsYDao;
import ru.yandex.webmaster3.storage.url.checker2.dao.UrlCheckResultsYDao;
import ru.yandex.webmaster3.storage.url.checker2.data.UrlCheckInfo;
import ru.yandex.webmaster3.storage.url.common.data.UrlCheckRequestData;
import ru.yandex.webmaster3.storage.url.common.data.UrlCheckRequestSource;
import ru.yandex.webmaster3.storage.url.checker2.data.UrlCheckResultData;
import ru.yandex.webmaster3.storage.util.ydb.exception.WebmasterYdbException;

import java.net.URL;
import java.util.Comparator;
import java.util.List;
import java.util.Optional;
import java.util.UUID;

/**
 * Created by leonidrom on 02/03/2017.
 */
@Service
@RequiredArgsConstructor(onConstructor_ = @Autowired)
public class UrlCheckRequestService {
    private static final Logger log = LoggerFactory.getLogger(UrlCheckRequestService.class);
    private static final int REQUESTS_FOR_HOST_PER_DAY_LIMIT = 100;

    private final UrlCheckRequestsYDao urlCheckRequestsYDao;
    private final UrlCheckResultsYDao urlCheckResultsYDao;

    public int getRequestsLeftForHostToday(WebmasterHostId hostId) {
        try {
            int todayRequests = (int)urlCheckRequestsYDao.getHostRequestsCountAfter(hostId,
                    DateTime.now().withTimeAtStartOfDay());
            return Math.max(0, REQUESTS_FOR_HOST_PER_DAY_LIMIT - todayRequests);
        } catch (WebmasterYdbException e) {
            throw new WebmasterException("Failed to get requests left for host",
                    new WebmasterErrorResponse.YDBErrorResponse(getClass(), e), e);
        }
    }

    public void deleteResultAndRequest(WebmasterHostId hostId, UUID requestId) {
        try {
            urlCheckRequestsYDao.deleteRequest(hostId, requestId);
            urlCheckResultsYDao.deleteResult(hostId, requestId);
        } catch (WebmasterYdbException e) {
            throw new WebmasterException("Failed to delete url check request/result",
                    new WebmasterErrorResponse.YDBErrorResponse(getClass(), e), e);
        }
    }

    public UrlCheckRequestData createRequest(WebmasterHostId hostId, URL url) {
        DateTime createdTime = DateTime.now();
        UUID requestId = UUIDs.timeBased();

        try {
            UrlCheckRequestData request = new UrlCheckRequestData(hostId, requestId, url, createdTime, UrlCheckRequestSource.URL_CHECK);
            urlCheckRequestsYDao.storeRequest(request);

            return request;
        } catch (WebmasterYdbException e) {
            throw new WebmasterException("Failed to create url check request",
                    new WebmasterErrorResponse.YDBErrorResponse(getClass(), e), e);
        }
    }

    public Optional<UrlCheckRequestData> getRequest(WebmasterHostId hostId, UUID requestId) {
        UrlCheckRequestData request;
        try {
            request = urlCheckRequestsYDao.getRequest(hostId, requestId);
        } catch (WebmasterYdbException e) {
            throw new WebmasterException("Failed to retrieve url check request",
                    new WebmasterErrorResponse.YDBErrorResponse(getClass(), e), e);
        }

        return Optional.ofNullable(request);
    }

    public List<UrlCheckRequestData> getRequests(WebmasterHostId hostId) {
        List<UrlCheckRequestData> reqs;
        try {
            reqs = urlCheckRequestsYDao.getRequests(hostId);
        } catch (WebmasterYdbException e) {
            throw new WebmasterException("Failed to retrieve url check request",
                    new WebmasterErrorResponse.YDBErrorResponse(getClass(), e), e);
        }

        reqs.sort(Comparator.comparing(UrlCheckRequestData::getCreatedTime).reversed());

        return reqs;
    }

    void storeResult(WebmasterHostId hostId, UUID requestId, UrlCheckInfo urlInfo) {
        DateTime completedTime = DateTime.now();
        try {
            urlCheckResultsYDao.storeResult(hostId, requestId, completedTime, urlInfo);
        } catch (WebmasterYdbException e) {
            throw new WebmasterException("Failed to store url check result",
                    new WebmasterErrorResponse.YDBErrorResponse(getClass(), e), e);

        }
    }

    public List<UrlCheckResultData> getResults(WebmasterHostId hostId) {
        try {
            return urlCheckResultsYDao.getResults(hostId);
        } catch (WebmasterYdbException e) {
            throw new WebmasterException("Failed to retrieve url check results",
                    new WebmasterErrorResponse.YDBErrorResponse(getClass(), e), e);
        }
    }

    public Optional<UrlCheckResultData> getResult(WebmasterHostId hostId, UUID requestId) {
        UrlCheckResultData resultData;
        try {
            resultData = urlCheckResultsYDao.getResult(hostId, requestId);
        } catch (WebmasterYdbException e) {
            throw new WebmasterException("Failed to retrieve url check result",
                    new WebmasterErrorResponse.YDBErrorResponse(getClass(), e), e);

        }

        return Optional.ofNullable(resultData);
    }
}
