package ru.yandex.webmaster3.storage.tools;

import java.util.Collections;
import java.util.List;
import java.util.UUID;

import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.collections4.CollectionUtils;
import org.jetbrains.annotations.NotNull;
import org.joda.time.DateTime;
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.data.WebmasterUser;
import ru.yandex.webmaster3.core.http.WebmasterErrorResponse;
import ru.yandex.webmaster3.core.util.IdUtils;
import ru.yandex.webmaster3.storage.user.UserTakeoutDataProvider;
import ru.yandex.webmaster3.storage.user.service.UserHostsService;
import ru.yandex.webmaster3.storage.util.ydb.exception.WebmasterYdbException;

/**
 * @author vsedaikina
 * 22.02.22
 */
@Slf4j
@Service
@RequiredArgsConstructor(onConstructor_ = {@Autowired})
public class ToolsRequestsLimitService implements UserTakeoutDataProvider {
    private static final int REQUESTS_FOR_USER_PER_DAY_LIMIT = 100;
    //unlim for user verified hosts

    private final ToolsRequestsPerUserYDao toolsRequestsPerUserYDao;
    private final UserHostsService userHostsService;

    public boolean tryRequest(long userId, String url, ToolType toolType) {
        try {
            log.info("Checking tool {} for user {} and url {}", toolType, userId, url);
            if (url == null) {
                return true; //no url, no limit
            }

            if (isUrlVerifiedForUser(userId, url)) {
                return true; //unlim for host owners
            }

            DateTime now = DateTime.now();
            DateTime dayStart = now.withTimeAtStartOfDay();
            List<ToolsRequestInfo> requests = toolsRequestsPerUserYDao.getAllHostRequestsByCreationDesc(userId, dayStart, toolType);
            long requestsMadeToday = requests
                    .stream()
                    .filter(r -> !r.getAddDate().isBefore(dayStart))
                    .count();

            log.info("If limit for tool {} and user {} exceeded {}", toolType, userId, (requestsMadeToday >= REQUESTS_FOR_USER_PER_DAY_LIMIT));

            return requestsMadeToday < REQUESTS_FOR_USER_PER_DAY_LIMIT; //if new request is available or not
        } catch (WebmasterYdbException e) {
            throw new WebmasterException("Failed to create tools limit request",
                    new WebmasterErrorResponse.YDBErrorResponse(getClass(), e), e);
        }
    }

    public void addUserRequest(long userId, String url, ToolType toolType) {
        if ((url == null) || (isUrlVerifiedForUser(userId, url))) {
            return; //no url, no limit || unlim for host owners
        }

        toolsRequestsPerUserYDao.insert(userId, UUID.randomUUID(), DateTime.now(), url, toolType);
    }

    @Override
    public @NotNull List<String> getTakeoutTables() {
        return List.of(toolsRequestsPerUserYDao.getTablePath());
    }

    @Override
    public void deleteUserData(WebmasterUser user) {
        toolsRequestsPerUserYDao.deleteForUser(user.getUserId());
    }

    private boolean isUrlVerifiedForUser(long userId, String url) {
        WebmasterHostId hostId;
        try {
            hostId = IdUtils.urlToHostId(url);
        } catch (WebmasterException e) {
            log.error("Error parsing {}", url);
            return true; //no need to check it if failed to parse host
        }

        return !CollectionUtils.isEmpty(userHostsService.getVerifiedHosts(new WebmasterUser(userId), Collections.singletonList(hostId)));
    }
}
