//! PulsingDot — self-scheduling animation that minimizes parent re-renders.
//!
//! Uses window.on_next_frame() with a 500ms delay to schedule exactly 1 repaint
//! per blink cycle. No continuous request_animation_frame loop.

use gpui::*;
use std::time::{Duration, Instant};

use crate::theme;

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

pub struct PulsingDot {
    status: DotStatus,
    size: f32,
    visible: bool,
    last_toggle: Instant,
}

impl PulsingDot {
    pub fn new(status: DotStatus, size: f32) -> Self {
        Self {
            status,
            size,
            visible: true,
            last_toggle: Instant::now(),
        }
    }

    fn should_pulse(&self) -> bool {
        matches!(self.status, DotStatus::Running | DotStatus::Stalled)
    }

    fn base_color(&self) -> Rgba {
        match self.status {
            DotStatus::Running => theme::GREEN,
            DotStatus::Idle => theme::OVERLAY0,
            DotStatus::Stalled => theme::PEACH,
            DotStatus::Done => theme::BLUE,
            DotStatus::Error => theme::RED,
        }
    }

    /// Start blink scheduling from context (after entity registered)
    pub fn start_blinking(&self, cx: &mut Context<Self>) {
        if !self.should_pulse() { return; }
        // Schedule first blink via background timer
        cx.spawn(async move |weak: WeakEntity<Self>, cx: &mut AsyncApp| {
            loop {
                cx.background_executor().timer(Duration::from_millis(500)).await;
                let ok = weak.update(cx, |dot, cx| {
                    dot.visible = !dot.visible;
                    dot.last_toggle = Instant::now();
                    cx.notify();
                });
                if ok.is_err() { break; }
            }
        }).detach();
    }
}

impl Render for PulsingDot {
    fn render(&mut self, _window: &mut Window, _cx: &mut Context<Self>) -> impl IntoElement {
        let color = if self.should_pulse() && !self.visible {
            theme::SURFACE1
        } else {
            self.base_color()
        };

        let r = (color.r * 255.0) as u32;
        let g = (color.g * 255.0) as u32;
        let b = (color.b * 255.0) as u32;
        let hex = rgba(r * 0x1000000 + g * 0x10000 + b * 0x100 + 0xFF);

        div()
            .w(px(self.size))
            .h(px(self.size))
            .rounded(px(self.size / 2.0))
            .bg(hex)
            .flex_shrink_0()
    }
}
