package com.lanyuanxiaoyao.service.monitor.metric;

import cn.hutool.core.util.StrUtil;
import com.lanyuanxiaoyao.service.common.Constants;
import com.lanyuanxiaoyao.service.common.entity.TableMeta;
import com.lanyuanxiaoyao.service.configuration.ExecutorProvider;
import com.lanyuanxiaoyao.service.forest.service.HudiService;
import com.lanyuanxiaoyao.service.forest.service.InfoService;
import io.micrometer.core.instrument.MeterRegistry;
import io.micrometer.core.instrument.Tag;
import java.util.concurrent.atomic.AtomicLong;
import org.eclipse.collections.api.factory.Lists;
import org.eclipse.collections.api.factory.Maps;
import org.eclipse.collections.api.list.ImmutableList;
import org.eclipse.collections.api.map.MutableMap;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Service;

import static com.lanyuanxiaoyao.service.common.Constants.MINUTE;

/**
 * Hudi表相关指标
 *
 * @author lanyuanxiaoyao
 * @date 2024-03-05
 */
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Service
public class HudiTableFilesCountMetrics extends Metrics {
    private static final Logger logger = LoggerFactory.getLogger(HudiTableFilesCountMetrics.class);

    private final MeterRegistry registry;
    private final InfoService infoService;
    private final HudiService hudiService;

    private final MutableMap<String, AtomicLong> fileCountCacheMap;
    private final MutableMap<String, AtomicLong> timelineFileCountCacheMap;

    public HudiTableFilesCountMetrics(MeterRegistry registry, InfoService infoService, HudiService hudiService) {
        this.registry = registry;
        this.infoService = infoService;
        this.hudiService = hudiService;

        fileCountCacheMap = Maps.mutable.empty();
        timelineFileCountCacheMap = Maps.mutable.empty();
    }

    @Override
    public String name() {
        return "Hudi表文件数量监控";
    }

    @Scheduled(fixedDelay = 30 * MINUTE, initialDelay = MINUTE)
    @Override
    public void update() {
        try {
            start();
            ImmutableList<TableMeta> metas = infoService.tableMetaList();
            setTotal(metas.size());
            metas
                    .asParallel(ExecutorProvider.EXECUTORS_2, 1)
                    .reject(meta -> StrUtil.isBlank(meta.getPulsarAddress()))
                    .forEach(meta -> {
                        try {
                            AtomicLong filecountCache = fileCountCacheMap.getIfAbsentPut(
                                    meta.getAlias(),
                                    registry.gauge(
                                            Constants.METRICS_HUDI_TABLE_FILE_COUNT,
                                            Lists.immutable.of(
                                                    Tag.of(Constants.METRICS_LABEL_FLINK_JOB_ID, meta.getJob().getId().toString()),
                                                    Tag.of(Constants.METRICS_LABEL_ALIAS, meta.getAlias()),
                                                    Tag.of(Constants.METRICS_LABEL_SCHEMA, meta.getSchema()),
                                                    Tag.of(Constants.METRICS_LABEL_TABLE, meta.getTable())
                                            ),
                                            new AtomicLong(0)
                                    )
                            );
                            AtomicLong timelineFileCountCache = timelineFileCountCacheMap.getIfAbsentPut(
                                    meta.getAlias(),
                                    registry.gauge(
                                            Constants.METRICS_HUDI_TABLE_TIMELINE_FILE_COUNT,
                                            Lists.immutable.of(
                                                    Tag.of(Constants.METRICS_LABEL_FLINK_JOB_ID, meta.getJob().getId().toString()),
                                                    Tag.of(Constants.METRICS_LABEL_ALIAS, meta.getAlias()),
                                                    Tag.of(Constants.METRICS_LABEL_SCHEMA, meta.getSchema()),
                                                    Tag.of(Constants.METRICS_LABEL_TABLE, meta.getTable())
                                            ),
                                            new AtomicLong(0)
                                    )
                            );

                            String hdfs = meta.getHudi().getTargetHdfsPath();
                            if (hudiService.existsHudiTable(hdfs)) {
                                Long count = hudiService.fileCount(hdfs);
                                filecountCache.set(count);

                                String timelineHdfs = hdfs + "/.hoodie";
                                timelineFileCountCache.set(hudiService.fileCount(timelineHdfs));
                            }
                        } catch (Exception exception) {
                            logger.warn("Get file count fail for {}", meta.getAlias(), exception);
                        }
                        finished();
                    });
        } finally {
            reset();
        }
    }
}
