/// PulsingDot — smooth pulse via 6 manual color steps. Zero CSS animation overhead.
///
/// 6 pre-computed color classes cycled every 200ms = 1.2s full pulse.
/// Each step: 1 class change → 1 Blitz repaint. No CSS transition engine.
/// Cost: 5 repaints/sec × 1 element = unmeasurable CPU.

use dioxus::prelude::*;
use std::sync::atomic::{AtomicU8, Ordering};
use std::sync::Arc;
use std::time::Duration;

#[derive(Clone, PartialEq)]
pub enum DotState {
    Running,
    Idle,
    Stalled,
    Done,
    Error,
}

const STEP_MS: u64 = 200;
const STEPS: u8 = 6;

#[component]
pub fn PulsingDot(state: DotState, size: Option<String>) -> Element {
    let should_pulse = matches!(state, DotState::Running | DotState::Stalled);
    let step = use_hook(|| Arc::new(AtomicU8::new(0)));

    if should_pulse {
        let s = step.clone();
        let updater = use_hook(|| dioxus::dioxus_core::schedule_update());

        use_hook(move || {
            std::thread::spawn(move || {
                loop {
                    std::thread::sleep(Duration::from_millis(STEP_MS));
                    s.store((s.load(Ordering::Relaxed) + 1) % STEPS, Ordering::Relaxed);
                    updater();
                }
            });
        });
    }

    let base = match state {
        DotState::Running => "dot-running",
        DotState::Idle => "dot-idle",
        DotState::Stalled => "dot-stalled",
        DotState::Done => "dot-done",
        DotState::Error => "dot-error",
    };

    let step_class = if should_pulse {
        match step.load(Ordering::Relaxed) {
            0 => "dot-s0", 1 => "dot-s1", 2 => "dot-s2",
            3 => "dot-s3", 4 => "dot-s4", _ => "dot-s5",
        }
    } else {
        "dot-s0"
    };

    let sz = size.unwrap_or_else(|| "8px".to_string());

    rsx! {
        span {
            class: "pulsing-dot {base} {step_class}",
            style: "width: {sz}; height: {sz};",
        }
    }
}
