//! Staging area for pattern start/stop, mute/solo, and prop changes before commit.

use crate::engine::{PatternChange, SequencerSnapshot};
use crate::model::bp_label;
use crate::state::StagedChange;

use super::App;

impl App {
    /// Toggle a pattern's staged state: unstage if already staged, else stage start or stop.
    pub fn stage_pattern_toggle(
        &mut self,
        bank: usize,
        pattern: usize,
        snapshot: &SequencerSnapshot,
    ) {
        let is_playing = snapshot.is_playing(bank, pattern);
        let pattern_data = self.project_state.project.pattern_at(bank, pattern);

        let existing = self.playback.staged_changes.iter().position(|c| {
            c.change.pattern_id().bank == bank && c.change.pattern_id().pattern == pattern
        });

        if let Some(idx) = existing {
            self.playback.staged_changes.remove(idx);
            self.ui
                .set_status(format!("{} unstaged", bp_label(bank, pattern)));
        } else if is_playing {
            self.playback.staged_changes.push(StagedChange {
                change: PatternChange::Stop { bank, pattern },
                quantization: pattern_data.quantization,
                sync_mode: pattern_data.sync_mode,
            });
            self.ui
                .set_status(format!("{} staged to stop", bp_label(bank, pattern)));
        } else {
            self.playback.staged_changes.push(StagedChange {
                change: PatternChange::Start { bank, pattern },
                quantization: pattern_data.quantization,
                sync_mode: pattern_data.sync_mode,
            });
            self.ui
                .set_status(format!("{} staged to play", bp_label(bank, pattern)));
        }
    }

    /// Commits staged pattern, mute/solo, and prop changes.
    /// Returns true if mute state changed (caller should send to sequencer).
    pub fn commit_staged_changes(&mut self) -> bool {
        let pattern_count = self.playback.staged_changes.len();
        let mute_count = self.playback.staged_mute_changes.len();
        let prop_count = self.playback.staged_prop_changes.len();

        if pattern_count == 0 && mute_count == 0 && prop_count == 0 {
            self.ui.set_status("No changes to commit".to_string());
            return false;
        }

        if pattern_count > 0 {
            self.playback
                .queued_changes
                .append(&mut self.playback.staged_changes);
        }

        let mute_changed = mute_count > 0;
        for change in self.playback.staged_mute_changes.drain() {
            match change {
                crate::state::StagedMuteChange::ToggleMute { bank, pattern } => {
                    self.mute.toggle_mute(bank, pattern);
                }
                crate::state::StagedMuteChange::ToggleSolo { bank, pattern } => {
                    self.mute.toggle_solo(bank, pattern);
                }
            }
        }

        for ((bank, pattern), props) in self.playback.staged_prop_changes.drain() {
            let pat = self.project_state.project.pattern_at_mut(bank, pattern);
            pat.name = props.name;
            pat.description = props.description;
            if let Some(len) = props.length {
                pat.set_length(len);
            }
            pat.speed = props.speed;
            pat.quantization = props.quantization;
            pat.sync_mode = props.sync_mode;
            pat.follow_up = props.follow_up;
            self.project_state.mark_dirty(bank, pattern);
        }

        let total = pattern_count + mute_count + prop_count;
        let status = format!("Committed {total} changes");
        self.ui.set_status(status);

        mute_changed
    }

    pub fn clear_staged_changes(&mut self) {
        let pattern_count = self.playback.staged_changes.len();
        let mute_count = self.playback.staged_mute_changes.len();
        let prop_count = self.playback.staged_prop_changes.len();

        if pattern_count == 0 && mute_count == 0 && prop_count == 0 {
            return;
        }

        self.playback.staged_changes.clear();
        self.playback.staged_mute_changes.clear();
        self.playback.staged_prop_changes.clear();

        let total = pattern_count + mute_count + prop_count;
        let status = format!("Cleared {total} staged changes");
        self.ui.set_status(status);
    }
}
