package ru.yandex.webmaster3.viewer.http.searchurl.events;

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

import com.google.protobuf.InvalidProtocolBufferException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.joda.time.DateTime;
import org.springframework.beans.factory.annotation.Autowired;
import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.data.WebmasterHostId;
import ru.yandex.webmaster3.core.http.ReadAction;
import ru.yandex.webmaster3.core.http.UserContext;
import ru.yandex.webmaster3.core.metrics.Category;
import ru.yandex.webmaster3.core.util.TimeUtils;
import ru.yandex.webmaster3.proto.dashboard.cache.DashboardCache;
import ru.yandex.webmaster3.storage.cache.DashboardCacheService;
import ru.yandex.webmaster3.storage.cache.DashboardType;
import ru.yandex.webmaster3.storage.searchurl.offline.SearchBaseImportTablesService;
import ru.yandex.webmaster3.storage.searchurl.offline.dao.SearchBaseImportedTable;
import ru.yandex.webmaster3.storage.searchurl.offline.data.SearchBaseImportTaskType;
import ru.yandex.webmaster3.storage.searchurl.samples.dao.SearchUrlFreshUrlSampleCHDao;
import ru.yandex.webmaster3.storage.searchurl.samples.data.SearchUrlEventSample;
import ru.yandex.webmaster3.storage.searchurl.samples.data.SearchUrlEventType;
import ru.yandex.webmaster3.storage.util.clickhouse2.condition.Condition;
import ru.yandex.webmaster3.viewer.util.DashboardUtils;

/**
 * @author aherman
 */
@RequiredArgsConstructor(onConstructor_ = @Autowired)
@Slf4j
@ReadAction
@Category("searchurl")
public class SearchUrlEventSamplesDashboardAction extends SearchUrlEventSamplesAction {
    private static final DashboardType DASHBOARD_TYPE = DashboardType.SEARCH_URL_SAMPLES;

    private final DashboardCacheService dashboardCacheService;
    private final SearchBaseImportTablesService searchBaseImportTablesService;
    private final SearchUrlFreshUrlSampleCHDao searchUrlFreshUrlSampleCHDao;

    @Override
    public SearchUrlEventSamplesResponse process(SearchUrlEventSamplesRequest request) throws WebmasterException {
        String cacheKey = createKey(request.getHostId());

        try {
            Optional<List<SearchUrlEventSample>> cachedSamples = dashboardCacheService
                    .getData(request.getHostId(), DASHBOARD_TYPE, cacheKey, (valueBytes) -> {
                        DashboardCache.SearchUrlSamplesCache susc;
                        try {
                            susc = DashboardCache.SearchUrlSamplesCache.parseFrom(valueBytes);
                        } catch (InvalidProtocolBufferException e) {
                            log.error("Unable to read value", e);
                            return Optional.empty();
                        }
                        List<SearchUrlEventSample> result = new ArrayList<>();
                        for (int i = 0; i < susc.getSamplesCount(); i++) {
                            DashboardCache.SearchUrlSamplesCache.SearchUrlSample samples = susc.getSamples(i);
                            SearchUrlEventType eventType =
                                    SearchUrlEventType.R.fromValueOrNull(samples.getEventType());
                            if (eventType != null) {
                                result.add(new SearchUrlEventSample(
                                        samples.getPath(),
                                        samples.getUrl(),
                                        "",
                                        DashboardUtils.intToLocalDate(samples.getLastAccess()),
                                        DashboardUtils.intToLocalDateTime(samples.getSearchBaseDate()),
                                        eventType,
                                        null
                                ));
                            }
                        }
                        return Optional.of(result);
                    });
            if (cachedSamples.isPresent()) {
                log.debug("From cache: {} {} {}", request.getHostId(), DASHBOARD_TYPE, cacheKey);
                return new SearchUrlEventSamplesResponse(cachedSamples.get().size(), cachedSamples.get());
            }
        } catch (Exception e) {
            log.error("Unable to read cached value: {} {} {}", request.getHostId(), DASHBOARD_TYPE, cacheKey, e);
        }

        UserContext.setUserId(request.getUserId());
        List<SearchUrlEventSample> samples = searchUrlSamplesService.getSearchUrlEventSamplesLight(request.getHostId(),
                Condition.trueCondition(),Condition.trueCondition(),
                request.getP() * request.getPSize(), request.getPSize());
        try {
            DashboardCache.SearchUrlSamplesCache.Builder susc = DashboardCache.SearchUrlSamplesCache.newBuilder();
            for (SearchUrlEventSample sample : samples) {
                susc.addSamples(
                        DashboardCache.SearchUrlSamplesCache.SearchUrlSample.newBuilder()
                                .setEventType(sample.getEventType().value())
                                .setPath(sample.getPath())
                                .setUrl(sample.getUrl())
                                .setLastAccess(DashboardUtils.localDateToInt(sample.getLastAccess()))
                                .setSearchBaseDate(DashboardUtils.localDateToInt(sample.getSearchBaseDate()))
                );
            }
            dashboardCacheService
                    .saveData(request.getHostId(), DASHBOARD_TYPE, cacheKey, susc.build().toByteArray());
        } catch (Exception e) {
            log.error("Unable to update cached value: {} {} {}", request.getHostId(), DASHBOARD_TYPE, cacheKey, e);
        }

        return new SearchUrlEventSamplesResponse(samples.size(), samples);
    }

    /**
     * В качестве ключа используем дату базы для самого свежего примера
     *
     * @return
     * @param hostId
     */
    private String createKey(WebmasterHostId hostId) {
        SearchBaseImportedTable table = searchBaseImportTablesService.getTable(
                SearchBaseImportTaskType.SEARCH_URL_EVENT_SAMPLES);
        long baseSwitchUnixTime = TimeUtils.toUnixTimestamp(table.getBaseUpdateInfo().getBaseSwitchDate());

        long maxFreshSampleUnixTime = 0;
        DateTime maxFreshSampleDate =  searchUrlFreshUrlSampleCHDao.getMaxBaseDate(hostId);
        if (maxFreshSampleDate != null) {
            maxFreshSampleUnixTime = TimeUtils.toUnixTimestamp(maxFreshSampleDate);
        }

        long keyUnixTime = Long.max(baseSwitchUnixTime, maxFreshSampleUnixTime);
        return String.valueOf(keyUnixTime);
    }
}
