use crate::telemetry::tokio_runtime_metrics::metrics::{tokio_runtime_core, tokio_runtime_worker};
use std::sync::Arc;
use std::sync::atomic::Ordering;
use tokio::runtime::{Handle, RuntimeMetrics};

pub(super) struct RuntimeHandle {
    pub(super) runtime_name: Option<Arc<str>>,
    pub(super) runtime_id: Option<usize>,
    pub(super) handle: Handle,
}

impl RuntimeHandle {
    pub(super) fn record_sample(&mut self) {
        let metrics = self.handle.metrics();

        self.record_global_metrics(&metrics);

        for worker_idx in 0..metrics.num_workers() {
            self.record_worker_metrics(&metrics, worker_idx);
        }
    }

    fn record_global_metrics(&mut self, metrics: &RuntimeMetrics) {
        tokio_runtime_core::workers(&self.runtime_name, self.runtime_id)
            .set(metrics.num_workers() as u64);

        tokio_runtime_core::blocking_threads(&self.runtime_name, self.runtime_id)
            .set(metrics.num_blocking_threads() as u64);

        tokio_runtime_core::num_alive_tasks(&self.runtime_name, self.runtime_id)
            .set(metrics.num_alive_tasks() as u64);

        tokio_runtime_core::idle_blocking_threads(&self.runtime_name, self.runtime_id)
            .set(metrics.num_idle_blocking_threads() as u64);

        tokio_runtime_core::remote_schedules_total(&self.runtime_name, self.runtime_id)
            .inner()
            .store(metrics.remote_schedule_count(), Ordering::SeqCst);

        tokio_runtime_core::budget_forced_yields_total(&self.runtime_name, self.runtime_id)
            .inner()
            .store(metrics.budget_forced_yield_count(), Ordering::SeqCst);

        tokio_runtime_core::io_driver_fd_registrations_total(&self.runtime_name, self.runtime_id)
            .inner()
            .store(metrics.io_driver_fd_registered_count(), Ordering::SeqCst);

        tokio_runtime_core::io_driver_fd_deregistrations_total(&self.runtime_name, self.runtime_id)
            .inner()
            .store(metrics.io_driver_fd_deregistered_count(), Ordering::SeqCst);

        tokio_runtime_core::io_driver_fd_readies_total(&self.runtime_name, self.runtime_id)
            .inner()
            .store(metrics.io_driver_ready_count(), Ordering::SeqCst);

        tokio_runtime_core::global_queue_depth(&self.runtime_name, self.runtime_id)
            .set(metrics.global_queue_depth() as u64);

        tokio_runtime_core::blocking_queue_depth(&self.runtime_name, self.runtime_id)
            .set(metrics.blocking_queue_depth() as u64);
    }

    fn record_worker_metrics(&mut self, metrics: &RuntimeMetrics, worker_idx: usize) {
        tokio_runtime_worker::parks_total(&self.runtime_name, self.runtime_id, worker_idx)
            .inner()
            .store(metrics.worker_park_count(worker_idx), Ordering::SeqCst);

        tokio_runtime_worker::noops_total(&self.runtime_name, self.runtime_id, worker_idx)
            .inner()
            .store(metrics.worker_noop_count(worker_idx), Ordering::SeqCst);

        tokio_runtime_worker::task_steals_total(&self.runtime_name, self.runtime_id, worker_idx)
            .inner()
            .store(metrics.worker_steal_count(worker_idx), Ordering::SeqCst);

        tokio_runtime_worker::steal_operations_total(
            &self.runtime_name,
            self.runtime_id,
            worker_idx,
        )
        .inner()
        .store(
            metrics.worker_steal_operations(worker_idx),
            Ordering::SeqCst,
        );

        tokio_runtime_worker::polls_total(&self.runtime_name, self.runtime_id, worker_idx)
            .inner()
            .store(metrics.worker_poll_count(worker_idx), Ordering::SeqCst);

        tokio_runtime_worker::busy_duration_micros_total(
            &self.runtime_name,
            self.runtime_id,
            worker_idx,
        )
        .inner()
        .store(
            metrics.worker_total_busy_duration(worker_idx).as_micros() as u64,
            Ordering::SeqCst,
        );

        tokio_runtime_worker::local_schedules_total(
            &self.runtime_name,
            self.runtime_id,
            worker_idx,
        )
        .inner()
        .store(
            metrics.worker_local_schedule_count(worker_idx),
            Ordering::SeqCst,
        );

        tokio_runtime_worker::overflows_total(&self.runtime_name, self.runtime_id, worker_idx)
            .inner()
            .store(metrics.worker_overflow_count(worker_idx), Ordering::SeqCst);

        tokio_runtime_worker::local_queue_depth(&self.runtime_name, self.runtime_id, worker_idx)
            .set(metrics.worker_local_queue_depth(worker_idx) as u64);

        tokio_runtime_worker::mean_poll_time_micros(
            &self.runtime_name,
            self.runtime_id,
            worker_idx,
        )
        .set(metrics.worker_mean_poll_time(worker_idx).as_micros() as u64);
    }
}
