//! Sends pattern data, mute state, and queued start/stop changes to the sequencer thread.

use crossbeam_channel::Sender;

use crate::engine::{PatternChange, PatternSnapshot, SeqCommand, StepSnapshot};

use super::App;

impl App {
    /// Drain staged start/stop changes and send them to the sequencer.
    pub fn flush_queued_changes(&mut self, cmd_tx: &Sender<SeqCommand>) {
        for staged in self.playback.queued_changes.drain(..) {
            match staged.change {
                PatternChange::Start { bank, pattern } => {
                    let _ = cmd_tx.send(SeqCommand::PatternStart {
                        bank,
                        pattern,
                        quantization: staged.quantization,
                        sync_mode: staged.sync_mode,
                    });
                }
                PatternChange::Stop { bank, pattern } => {
                    let _ = cmd_tx.send(SeqCommand::PatternStop {
                        bank,
                        pattern,
                        quantization: staged.quantization,
                    });
                }
            }
        }
    }

    pub fn send_mute_state(&self, cmd_tx: &Sender<SeqCommand>) {
        let _ = cmd_tx.send(SeqCommand::SetMuteState {
            muted: self.mute.muted.clone(),
            soloed: self.mute.soloed.clone(),
        });
    }

    /// Send the periodic script to the sequencer if dirty.
    pub fn flush_dirty_script(&mut self, cmd_tx: &Sender<SeqCommand>) {
        if self.script_editor.dirty {
            self.script_editor.dirty = false;
            let _ = cmd_tx.send(SeqCommand::ScriptUpdate {
                script: self.project_state.project.script.clone(),
                speed: self.project_state.project.script_speed,
                length: self.project_state.project.script_length,
            });
        }
    }

    /// Snapshot and send all dirty patterns to the sequencer. Returns true if any were sent.
    pub fn flush_dirty_patterns(&mut self, cmd_tx: &Sender<SeqCommand>) -> bool {
        let dirty = self.project_state.take_dirty();
        let had_dirty = !dirty.is_empty();
        for (bank, pattern) in dirty {
            let pat = self.project_state.project.pattern_at(bank, pattern);
            let snapshot = PatternSnapshot {
                speed: pat.speed,
                length: pat.length,
                steps: pat
                    .steps
                    .iter()
                    .take(pat.length)
                    .map(|s| StepSnapshot {
                        active: s.active,
                        script: s.script.clone(),
                        source: s.source,
                    })
                    .collect(),
                quantization: pat.quantization,
                sync_mode: pat.sync_mode,
                follow_up: pat.follow_up,
            };
            let _ = cmd_tx.send(SeqCommand::PatternUpdate {
                bank,
                pattern,
                data: snapshot,
            });
        }
        had_dirty
    }
}
