package ru.yandex.webmaster3.monitoring.importanturls;

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

import org.joda.time.DateTime;
import org.joda.time.format.DateTimeFormat;
import org.joda.time.format.DateTimeFormatter;
import org.springframework.beans.factory.annotation.Required;
import org.springframework.scheduling.annotation.Scheduled;

import ru.yandex.webmaster3.core.solomon.HandleCommonMetricsService;
import ru.yandex.webmaster3.core.solomon.Indicators;
import ru.yandex.webmaster3.core.solomon.SolomonSensor;
import ru.yandex.webmaster3.storage.host.CommonDataState;
import ru.yandex.webmaster3.storage.host.CommonDataType;
import ru.yandex.webmaster3.storage.settings.dao.CommonDataStateYDao;
import ru.yandex.webmaster3.storage.util.yt.YtException;
import ru.yandex.webmaster3.storage.util.yt.YtNode;
import ru.yandex.webmaster3.storage.util.yt.YtPath;
import ru.yandex.webmaster3.storage.util.yt.YtService;

/**
 * Created by ifilippov5 on 21.08.17.
 */
public class ImportantUrlsMonitoringService {

    private static final String ATTR_LAST_PROCESSED = "modification_time";
    private static final DateTimeFormatter modificationDateTimeFormat = DateTimeFormat.forPattern("yyyy-MM-dd'T'HH:mm:ss.SSSSSS'Z'");

    private static final String SECTION_LABEL_VALUE = "important_urls";
    private static final String EXPORTED_URLS_DATA_TYPE = "exported_urls";
    private static final String IMPORTED_STATUSES_URLS_DATA_TYPE = "imported_statuses";
    private static final int AVERAGE_SENSORS_SIZE = 600;

    private HandleCommonMetricsService handleCommonMetricsService;
    private YtService ytService;
    private YtPath outputYtTablePath;
    private CommonDataStateYDao commonDataStateYDao;

    private boolean enabled;
    private long refreshIntervalSeconds;

    @Scheduled(cron = "${webmaster3.monitoring.solomon.importanturls.refresh-cron}")
    private void push() throws Exception {
        if (!enabled) {
            return;
        }

        long now = System.currentTimeMillis();
        List<SolomonSensor> sensors = new ArrayList<>();

        long ytModificationTime = getDataUpdateTimeForTableOnYT(outputYtTablePath).getMillis();
        sensors.add(SolomonSensor.createAligned(refreshIntervalSeconds, (now - ytModificationTime) / 1000L)
                .withLabel(SolomonSensor.LABEL_SECTION, SECTION_LABEL_VALUE)
                .withLabel(SolomonSensor.LABEL_INDICATOR, Indicators.DATA_AGE)
                .withLabel(SolomonSensor.LABEL_DATA_TYPE, EXPORTED_URLS_DATA_TYPE));

        CommonDataState cds = commonDataStateYDao.getValue(CommonDataType.LAST_IMPORTANT_URLS_STATUSES_IMPORT2);
        long lastImport = cds == null ? 0L : Long.parseLong(cds.getValue());
        sensors.add(SolomonSensor.createAligned(refreshIntervalSeconds, (now - lastImport * 1000L) / 1000L)
                .withLabel(SolomonSensor.LABEL_SECTION, SECTION_LABEL_VALUE)
                .withLabel(SolomonSensor.LABEL_INDICATOR, Indicators.DATA_AGE)
                .withLabel(SolomonSensor.LABEL_DATA_TYPE, IMPORTED_STATUSES_URLS_DATA_TYPE));

        handleCommonMetricsService.handle(sensors, AVERAGE_SENSORS_SIZE);
    }

    private DateTime getDataUpdateTimeForTableOnYT(YtPath tablePath) throws YtException, InterruptedException {
        return ytService.withoutTransactionQuery(cypressService -> {
            if (!cypressService.exists(tablePath)) {
                throw new YtException("Table " + tablePath + " is not exist");
            }
            YtNode result = cypressService.getNode(tablePath);
            String modificationTimeAsText = result.getNodeMeta().get(ATTR_LAST_PROCESSED).asText();
            DateTime dateTime = DateTime.parse(modificationTimeAsText, modificationDateTimeFormat);

            return dateTime;
        });
    }

    @Required
    public void setHandleCommonMetricsService(HandleCommonMetricsService handleCommonMetricsService) {
        this.handleCommonMetricsService = handleCommonMetricsService;
    }

    @Required
    public void setYtService(YtService ytService) {
        this.ytService = ytService;
    }

    @Required
    public void setOutputYtTablePath(YtPath outputYtTablePath) {
        this.outputYtTablePath = outputYtTablePath;
    }

    @Required
    public void setCommonDataStateYDao(CommonDataStateYDao commonDataStateYDao) {
        this.commonDataStateYDao = commonDataStateYDao;
    }

    @Required
    public void setEnabled(boolean enabled) {
        this.enabled = enabled;
    }

    @Required
    public void setRefreshIntervalSeconds(long refreshIntervalSeconds) {
        this.refreshIntervalSeconds = refreshIntervalSeconds;
    }
}
