package com.lanyuanxiaoyao.service.sync.functions;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.map.MapUtil;
import com.lanyuanxiaoyao.service.common.Constants;
import com.lanyuanxiaoyao.service.common.entity.FlinkJob;
import com.lanyuanxiaoyao.service.common.entity.Record;
import com.lanyuanxiaoyao.service.common.entity.TableMeta;
import com.lanyuanxiaoyao.service.sync.configuration.GlobalConfiguration;
import com.lanyuanxiaoyao.service.sync.metrics.CountMetric;
import com.lanyuanxiaoyao.service.sync.utils.MetricsUtils;
import java.util.List;
import java.util.Map;
import java.util.function.Function;
import org.apache.flink.api.common.functions.RichFilterFunction;
import org.apache.flink.configuration.Configuration;
import org.apache.flink.runtime.state.FunctionInitializationContext;
import org.apache.flink.runtime.state.FunctionSnapshotContext;
import org.apache.flink.streaming.api.checkpoint.CheckpointedFunction;

/**
 * 操作类型过滤算子
 *
 * @author ZhangJiacheng
 * @date 2022-06-12
 */
public class OperationTypeFilter extends RichFilterFunction<Record> implements CheckpointedFunction {
    private final CountMetric insertRateMetric;
    private final CountMetric updateRateMetric;
    private final CountMetric deleteRateMetric;
    private final CountMetric ddlRateMetric;
    private final CountMetric unknownRateMetric;
    private final List<CountMetric> metrics;
    private final GlobalConfiguration globalConfiguration;

    public OperationTypeFilter(GlobalConfiguration globalConfiguration, FlinkJob flinkJob, TableMeta tableMeta) {
        this.globalConfiguration = globalConfiguration;

        Function<String, Map<String, String>> fillTags = operator -> MapUtil.<String, String>builder()
                .put(Constants.METRICS_LABEL_TYPE, operator)
                .build();

        insertRateMetric = new CountMetric(globalConfiguration, Constants.METRICS_SYNC_SOURCE_OPERATION_TYPE_RECEIVE, flinkJob, tableMeta, fillTags.apply(Constants.INSERT));
        updateRateMetric = new CountMetric(globalConfiguration, Constants.METRICS_SYNC_SOURCE_OPERATION_TYPE_RECEIVE, flinkJob, tableMeta, fillTags.apply(Constants.UPDATE));
        deleteRateMetric = new CountMetric(globalConfiguration, Constants.METRICS_SYNC_SOURCE_OPERATION_TYPE_RECEIVE, flinkJob, tableMeta, fillTags.apply(Constants.DELETE));
        ddlRateMetric = new CountMetric(globalConfiguration, Constants.METRICS_SYNC_SOURCE_OPERATION_TYPE_RECEIVE, flinkJob, tableMeta, fillTags.apply(Constants.DDL));
        unknownRateMetric = new CountMetric(globalConfiguration, Constants.METRICS_SYNC_SOURCE_OPERATION_TYPE_RECEIVE, flinkJob, tableMeta, fillTags.apply(Constants.UNKNOWN));

        metrics = ListUtil.toList(insertRateMetric, updateRateMetric, deleteRateMetric, ddlRateMetric, unknownRateMetric);
    }

    @Override
    public void open(Configuration parameters) throws Exception {
        super.open(parameters);

        // 初始化指标
        MetricsUtils.createMakePointTimer(globalConfiguration, metrics);
    }

    @Override
    public boolean filter(Record record) {
        String opType = record.getStatement().getOpType();
        switch (opType) {
            case Constants.INSERT:
                insertRateMetric.increment();
                break;
            case Constants.UPDATE:
                updateRateMetric.increment();
                break;
            case Constants.DELETE:
                deleteRateMetric.increment();
                break;
            case Constants.DDL:
                ddlRateMetric.increment();
                break;
            default:
                unknownRateMetric.increment();
        }
        return !Constants.DDL.equals(record.getStatement().getOpType());
    }

    @Override
    public void initializeState(FunctionInitializationContext context) {
    }

    @Override
    public void snapshotState(FunctionSnapshotContext context) {
        MetricsUtils.publishAllMetrics(metrics);
    }
}
