// Copyright 2025 PingCAP, Inc.

use lazy_static::lazy_static;
use prometheus::*;
use prometheus_static_metric::*;

make_static_metric! {
    pub struct RepTxnFileCounter: IntCounter {
        "type" => {
            lock,
            commit,
            rollback,
        },
    }
    pub struct RepFetchWalCounter: IntCounter {
        "type" => {
            fetch_request,
            emit_batch,
            recv_target,
            no_target,
            refresh_store,
            refresh_store_err,
        }
    }
    pub struct RepShardLoadResultCounter: IntCounter {
        "result" => {
            ok,
            error,
            timeout,
            canceled,
            destroyed,
        }
    }
}

lazy_static! {
    // Sync WAL lag metrics.
    pub static ref REP_SYNC_WAL_TS: IntGauge = register_int_gauge!(
        "tikv_cdc_rep_sync_wal_ts",
        "The latest timestamp of sync WAL (milliseconds)"
    )
    .unwrap();
    pub static ref REP_SYNC_WAL_TS_LAG: IntGauge = register_int_gauge!(
        "tikv_cdc_rep_sync_wal_ts_lag",
        "The lag between the sync WAL timestamp and now (milliseconds)"
    )
    .unwrap();
    pub static ref REP_SYNC_WAL_TS_LAG_HISTOGRAM: Histogram = register_histogram!(
        "tikv_cdc_rep_sync_wal_ts_lag_seconds",
        "Bucketed histogram of the gap between sync WAL timestamp and now",
        exponential_buckets(0.001, 2.0, 24).unwrap()
    )
    .unwrap();

    // WalTargetFetcher metrics.
    pub static ref REP_FEATCH_WAL_TARGET_COUNTER: IntCounterVec = register_int_counter_vec!(
        "tikv_cdc_rep_fetch_wal_target_counter",
        "Total number of fetching WAL target events",
        &["type", "reason"]
    )
    .unwrap();

    // WalFetcher metrics.
    pub static ref REP_FETCH_WAL_COUNTER_VEC: RepFetchWalCounter = register_static_int_counter_vec!(
        RepFetchWalCounter,
        "tikv_cdc_rep_fetch_wal_counter",
        "Counter for fetching WAL events",
        &["type"]
    )
    .unwrap();
    pub static ref REP_FETCH_WAL_ADVANCE_TARGET_TS: IntGauge = register_int_gauge!(
        "tikv_cdc_rep_fetch_advance_target_ts",
        "The latest advanced timestamp of WalFetcher (milliseconds)"
    )
    .unwrap();
    pub static ref REP_FETCH_WAL_INFLIGHT: IntGauge = register_int_gauge!(
        "tikv_cdc_rep_fetch_wal_inflight",
        "In-flight WAL fetch tasks"
    )
    .unwrap();
    pub static ref REP_FETCH_WAL_DURATION: Histogram = register_histogram!(
        "tikv_cdc_rep_fetch_wal_duration_seconds",
        "Bucketed histogram of fetch WAL duration",
        exponential_buckets(0.1, 2.0, 16).unwrap() // 0.1s ~ 100m
    ).unwrap();
    pub static ref REP_FETCH_STORE_WAL_COUNTER: IntCounterVec = register_int_counter_vec!(
        "tikv_cdc_rep_fetch_store_wal_counter",
        "Counter of fetch store WAL",
        &["store", "result"]
    )
    .unwrap();
    pub static ref REP_FETCH_STORE_WAL_DURATION: HistogramVec = register_histogram_vec!(
        "tikv_cdc_rep_fetch_store_wal_duration_seconds",
        "Bucketed histogram of fetch store WAL duration",
        &["store"],
        exponential_buckets(0.1, 2.0, 16).unwrap() // 0.1s ~ 100m
    ).unwrap();
    pub static ref REP_FETCH_STORE_WAL_BYTES: IntCounterVec = register_int_counter_vec!(
        "tikv_cdc_rep_fetch_store_wal_bytes_total",
        "Total fetched bytes for update store",
        &["store", "source"]
    )
    .unwrap();
    pub static ref REP_FETCH_STORE_WAL_EPOCH_LAG: IntGaugeVec = register_int_gauge_vec!(
        "tikv_cdc_rep_fetch_store_wal_epoch_lag",
        "Epoch lag between store progress and first target",
        &["store"],
    ).unwrap();

    // Append WAL metrics.
    pub static ref REP_APPEND_STORE_WAL_COUNTER: IntCounterVec = register_int_counter_vec!(
        "tikv_cdc_rep_append_store_wal_counter",
        "Counter of append store WAL",
        &["store", "result"]
    )
    .unwrap();
    pub static ref REP_APPEND_STORE_WAL_DURATION: HistogramVec = register_histogram_vec!(
        "tikv_cdc_rep_append_store_wal_duration_seconds",
        "Bucketed histogram of append a fetched WAL batch",
        &["store"],
        exponential_buckets(0.01, 2.0, 20).unwrap() // 0.01s ~ 2.9h
    )
    .unwrap();
    pub static ref REP_APPEND_STORE_WAL_BYTES: IntCounterVec = register_int_counter_vec!(
        "tikv_cdc_rep_append_store_wal_bytes_total",
        "Total appended WAL bytes",
        &["store"]
    )
    .unwrap();

    // Scan locks metrics.
    pub static ref REP_SCAN_LOCKS_DURATION_HISTOGRAM: Histogram = register_histogram!(
        "tikv_cdc_rep_scan_locks_duration_seconds",
        "Bucketed histogram of replication worker scan locks duration",
        exponential_buckets(0.005, 2.0, 20).unwrap()
    )
    .unwrap();
    pub static ref REP_SCAN_LOCKS_BYTES: IntCounter = register_int_counter!(
        "tikv_cdc_rep_scan_locks_bytes_total",
        "Total fetched bytes of replication worker scan locks"
    )
    .unwrap();
    pub static ref REP_SCAN_LOCKS_TASKS: IntGaugeVec = register_int_gauge_vec!(
        "tikv_cdc_rep_scan_locks_tasks",
        "Total number of replication worker scan locks tasks",
        &["type"]
    )
    .unwrap();

    // GC safepoint metrics.
    pub static ref REP_SAFEPOINT_EVENTS_COUNTER: IntCounterVec = register_int_counter_vec!(
        "tikv_cdc_rep_safepoint_events_counter",
        "Total number of changefeed safepoint events",
        &["type", "keyspace", "reason"]
    )
    .unwrap();
    pub static ref REP_KEYSPACE_SERVICE_SAFEPOINT: IntGaugeVec = register_int_gauge_vec!(
        "tikv_cdc_rep_keyspace_service_safepoint",
        "The value of keyspace service safepoint",
        &["keyspace", "type"]
    )
    .unwrap();

    // Txn file operations metrics.
    pub static ref REP_TXN_FILE_COUNTER_VEC: RepTxnFileCounter = register_static_int_counter_vec!(
        RepTxnFileCounter,
        "tikv_cdc_rep_txn_file_counter",
        "Counter for txn file operations",
        &["type"]
    )
    .unwrap();

    // Resolved locks metrics.
    pub static ref REP_LIVE_LOCKS: IntCounter = register_int_counter!(
        "tikv_cdc_rep_live_locks_total",
        "Total number of live locks after resolving scan locks"
    )
    .unwrap();
    pub static ref REP_RESOLVED_LOCKS: IntCounter = register_int_counter!(
        "tikv_cdc_rep_resolved_locks_total",
        "Total number of resolved locks after resolving scan locks"
    )
    .unwrap();

    // Lazy shard loading metrics.
    pub static ref REP_LOADED_SHARDS: IntGauge = register_int_gauge!(
        "tikv_cdc_rep_loaded_shards",
        "Number of kvengine shards currently loaded in replication worker"
    )
    .unwrap();
    pub static ref REP_SHARD_LOAD_IN_FLIGHT: IntGauge = register_int_gauge!(
        "tikv_cdc_rep_shard_load_in_flight",
        "Number of region shard loads currently in-flight (deduplicated by region)"
    )
    .unwrap();
    pub static ref REP_SHARD_LOAD_DURATION: Histogram = register_histogram!(
        "tikv_cdc_rep_shard_load_duration_seconds",
        "Bucketed histogram of per-region shard load duration (prepare + load + recover)",
        exponential_buckets(0.01, 2.0, 20).unwrap() // 0.01s ~ 1.46h
    )
    .unwrap();
    pub static ref REP_SHARD_LOAD_TOTAL: RepShardLoadResultCounter = register_static_int_counter_vec!(
        RepShardLoadResultCounter,
        "tikv_cdc_rep_shard_load_total",
        "Total number of per-region shard load results",
        &["result"]
    )
    .unwrap();
    pub static ref REP_PENDING_REGISTERS: IntGauge = register_int_gauge!(
        "tikv_cdc_rep_pending_registers",
        "Number of pending CDC register requests waiting for shard loading"
    )
    .unwrap();

}
