// pipeline.rs — 完整替换

use std::time::{Duration, Instant};
use crate::output::{Output, Source};

pub struct Pipeline {
    min: f64,
    max: f64,
    pub step: f64,
    rate: Duration,
    output: Box<dyn Output>,

    pub current_value: f64,
    last_write: Instant,
    pending: bool,
    pending_source: Source,
}

impl Pipeline {
    pub fn new(
        min: f64, max: f64, step: f64, rate: Duration, output: Box<dyn Output>
    ) -> Self {
        Self {
            min, max, step, rate, output,
            current_value: min,
            last_write: Instant::now() - Duration::from_secs(10),
            pending: false,
            pending_source: Source::User,
        }
    }

    pub fn process_raw(&mut self, raw_value: f64, force: bool, source: Source) {
        let stepped = (raw_value / self.step).round() * self.step;
        let clamped = stepped.clamp(self.min, self.max);
        let changed = (clamped - self.current_value).abs() > f64::EPSILON;
        self.current_value = clamped;

        if !changed && !self.pending {
            return;
        }

        let now = Instant::now();
        if !force && now.duration_since(self.last_write) < self.rate {
            self.pending = true;
            self.pending_source = source;
            return;
        }

        self.pending = false;
        self.last_write = now;
        self.output.write(self.current_value, source);
    }

    pub fn flush_pending(&mut self) {
        if self.pending {
            self.pending = false;
            self.last_write = Instant::now();
            self.output.write(self.current_value, self.pending_source);
        }
    }

    pub fn force_write(&mut self, value: f64, source: Source) {
        let stepped = (value / self.step).round() * self.step;
        let clamped = stepped.clamp(self.min, self.max);
        self.current_value = clamped;
        self.output.write(clamped, source);
    }

    pub fn run_animation(&mut self, target: f64, duration: Duration, anim: String) {
        let start = Instant::now();
        let from = self.current_value;
        let to = target.clamp(self.min, self.max);

        loop {
            let elapsed = start.elapsed();
            if elapsed >= duration {
                self.process_raw(to, true, Source::User);
                break;
            }

            let t = elapsed.as_secs_f32() / duration.as_secs_f32();
            let progress = match anim.as_str() {
                "ease-out" => 1.0 - (1.0 - t).powi(2),
                _ => t,
            };

            let current = from + (to - from) * progress as f64;
            self.process_raw(current, false, Source::User);
            std::thread::sleep(Duration::from_millis(8));
        }
    }
}
