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.Setter;
import lombok.extern.slf4j.Slf4j;

import ru.yandex.webmaster3.core.WebmasterException;
import ru.yandex.webmaster3.core.http.ReadAction;
import ru.yandex.webmaster3.core.link.DatePoint;
import ru.yandex.webmaster3.core.metrics.Category;
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.host.CommonDataType;
import ru.yandex.webmaster3.storage.searchurl.samples.data.SearchUrlEventType;
import ru.yandex.webmaster3.storage.settings.SettingsService;
import ru.yandex.webmaster3.viewer.util.DashboardUtils;

/**
 * @author aherman
 */
@Slf4j
@ReadAction
@Category("searchurl")
public class SearchUrlEventHistoryDashboardAction extends SearchUrlEventHistoryAction {

    private static final DashboardType DASHBOARD_TYPE = DashboardType.SEARCH_URL_HISTORY;

    @Setter
    private DashboardCacheService dashboardCacheService;
    @Setter
    private SettingsService settingsService;

    @Override
    public SearchUrlEventHistoryResponse process(SearchUrlEventHistoryRequest request) throws WebmasterException {

        String cacheKey = createKey();
        try {
            Optional<List<SearchUrlEventHistoryResponse.SearchUrlHistory>> cachedHistories = dashboardCacheService
                    .getData(request.getHostId(), DASHBOARD_TYPE, cacheKey, (valueBytes) -> {
                        DashboardCache.SearchUrlHistoryCache duhc;
                        try {
                            duhc = DashboardCache.SearchUrlHistoryCache.parseFrom(valueBytes);
                        } catch (InvalidProtocolBufferException e) {
                            log.error("Unable to read value", e);
                            return Optional.empty();
                        }
                        List<SearchUrlEventHistoryResponse.SearchUrlHistory> result = new ArrayList<>();
                        for (int i = 0; i < duhc.getHistoriesCount(); i++) {
                            DashboardCache.SearchUrlHistoryCache.SearchUrlHistory h = duhc.getHistories(i);
                            SearchUrlEventType searchUrlEventType =
                                    SearchUrlEventType.R.fromValueOrNull(h.getIndicator());
                            if (searchUrlEventType == null) {
                                continue;
                            }
                            List<DatePoint> dataPoints = new ArrayList<>();
                            for (int j = 0; j < h.getDataCount(); j++) {
                                DashboardCache.DatePoint dp = h.getData(j);
                                dataPoints.add(new DatePoint(
                                        DashboardUtils.intToLocalDate(dp.getTime()),
                                        dp.getValue()
                                ));
                            }
                            result.add(new SearchUrlEventHistoryResponse.SearchUrlHistory(
                                    searchUrlEventType,
                                    dataPoints
                            ));
                        }
                        return Optional.of(result);
                    });
            if (cachedHistories.isPresent()) {
                log.debug("From cache: {} {} {}", request.getHostId(), DASHBOARD_TYPE, cacheKey);
                return new SearchUrlEventHistoryResponse(cachedHistories.get());
            }
        } catch (Exception e) {
            log.error("Unable to read cached value: {} {} {}", request.getHostId(), DASHBOARD_TYPE, cacheKey, e);
        }

        List<SearchUrlEventHistoryResponse.SearchUrlHistory> histories = getHistory(request);

        try {
            DashboardCache.SearchUrlHistoryCache.Builder duhc = DashboardCache.SearchUrlHistoryCache.newBuilder();

            for (SearchUrlEventHistoryResponse.SearchUrlHistory history : histories) {
                DashboardCache.SearchUrlHistoryCache.SearchUrlHistory.Builder h =
                        DashboardCache.SearchUrlHistoryCache.SearchUrlHistory.newBuilder();
                h.setIndicator(history.getIndicatorName().value());
                for (DatePoint datePoint : history.getData()) {
                    h.addData(DashboardCache.DatePoint.newBuilder()
                            .setTime(DashboardUtils.localDateToInt(datePoint.getTime()))
                            .setValue(datePoint.getValue())
                    );
                }
                duhc.addHistories(h);
            }
            dashboardCacheService
                    .saveData(request.getHostId(), DASHBOARD_TYPE, cacheKey, duhc.build().toByteArray());
        } catch (Exception e) {
            log.error("Unable to update cached value: {} {} {}", request.getHostId(), DASHBOARD_TYPE, cacheKey, e);
        }

        return new SearchUrlEventHistoryResponse(histories);
    }

    private String createKey() {
        return settingsService.getSettingCached(CommonDataType.LAST_IMPORTED_SITE_STRUCTURES, String::valueOf);
    }

}
