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.common.utils.NameHelper;
import com.lanyuanxiaoyao.service.configuration.ExecutorProvider;
import com.lanyuanxiaoyao.service.configuration.HudiServiceProperties;
import com.lanyuanxiaoyao.service.forest.service.InfoService;
import com.lanyuanxiaoyao.service.forest.service.PulsarService;
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;

/**
 * Pulsar
 *
 * @author lanyuanxiaoyao
 * @date 2024-03-05
 */
@SuppressWarnings("SpringJavaInjectionPointsAutowiringInspection")
@Service
public class PulsarBacklogMetrics extends Metrics {
    private static final Logger logger = LoggerFactory.getLogger(PulsarBacklogMetrics.class);

    private final MeterRegistry registry;
    private final InfoService infoService;
    private final PulsarService pulsarService;
    private final HudiServiceProperties hudiServiceProperties;

    private final MutableMap<String, AtomicLong> backlogMap;

    public PulsarBacklogMetrics(MeterRegistry registry, InfoService infoService, PulsarService pulsarService, HudiServiceProperties hudiServiceProperties) {
        this.registry = registry;
        this.infoService = infoService;
        this.pulsarService = pulsarService;
        this.hudiServiceProperties = hudiServiceProperties;

        backlogMap = Maps.mutable.empty();
    }

    @Override
    public String name() {
        return "Pulsar backlog监控";
    }

    @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 backlogCache = backlogMap.getIfAbsentPut(
                                    meta.getAlias(),
                                    registry.gauge(
                                            Constants.METRICS_PULSAR_BACKLOG,
                                            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 name = pulsarService.name(meta.getPulsarAddress());
                            if (StrUtil.isNotBlank(name)) {
                                Long backlog = pulsarService.backlog(name, meta.getTopic(), NameHelper.pulsarSubscriptionName(meta.getJob().getId(), meta.getAlias(), hudiServiceProperties.getSignature()));
                                backlogCache.set(backlog);
                                infoService.savePulsarBacklog(meta.getJob().getId(), meta.getAlias(), backlog);
                            }
                        } catch (Exception exception) {
                            logger.warn("Update pulsar backlog fail for {}", meta.getAlias(), exception);
                        }
                        finished();
                    });
        } finally {
            reset();
        }
    }
}
