use super::*;
use crate::state::StateData;

fn select_track_range(state: &mut StateData, from: &str, to: &str) {
    let from_index = state.tracks.iter().position(|t| t.name == from);
    let to_index = state.tracks.iter().position(|t| t.name == to);
    if let (Some(from_idx), Some(to_idx)) = (from_index, to_index) {
        let start = from_idx.min(to_idx);
        let end = from_idx.max(to_idx);
        let names: Vec<String> = state.tracks[start..=end]
            .iter()
            .map(|t| t.name.clone())
            .collect();
        let mut set = match &state.connection_view_selection {
            ConnectionViewSelection::Tracks(existing) => existing.clone(),
            _ => std::collections::HashSet::new(),
        };
        for name in names {
            state.selected.insert(name.clone());
            set.insert(name);
        }
        state.connection_view_selection = ConnectionViewSelection::Tracks(set);
    }
}

impl Maolan {
    pub(super) fn handle_track_selection_message(
        &mut self,
        message: Message,
    ) -> Option<Task<Message>> {
        match message {
            Message::ShiftPressed => {
                if !self.state.blocking_read().hw_loaded {
                    return Some(Task::none());
                }
                self.state.blocking_write().shift = true;
                None
            }
            Message::ShiftReleased => {
                if !self.state.blocking_read().hw_loaded {
                    return Some(Task::none());
                }
                self.state.blocking_write().shift = false;
                None
            }
            Message::CtrlPressed => {
                if !self.state.blocking_read().hw_loaded {
                    return Some(Task::none());
                }
                self.state.blocking_write().ctrl = true;
                None
            }
            Message::CtrlReleased => {
                if !self.state.blocking_read().hw_loaded {
                    return Some(Task::none());
                }
                self.state.blocking_write().ctrl = false;
                None
            }
            Message::SelectTrack(ref name) => {
                let now = Instant::now();
                let track_name = name.clone();
                let shift = self.state.blocking_read().shift;
                let ctrl = self.state.blocking_read().ctrl;
                let mut state = self.state.blocking_write();
                state.track_context_menu = None;
                if shift || ctrl {
                    state.connections_last_track_click = None;
                } else if let Some((last_track, last_time)) = &state.connections_last_track_click
                    && *last_track == track_name
                    && now.duration_since(*last_time) <= DOUBLE_CLICK.saturating_mul(2)
                {
                    state.connections_last_track_click = None;
                    return Some(Task::perform(async {}, move |_| {
                        Message::OpenTrackPlugins(track_name)
                    }));
                } else {
                    state.connections_last_track_click = Some((track_name.clone(), now));
                }

                if shift {
                    let anchor = state
                        .last_selected_track
                        .as_ref()
                        .filter(|anchor| state.tracks.iter().any(|t| t.name == **anchor))
                        .cloned();
                    if let Some(anchor) = anchor {
                        if !ctrl {
                            state.selected.clear();
                            state.connection_view_selection = ConnectionViewSelection::None;
                        }
                        select_track_range(&mut state, &anchor, name);
                    } else if ctrl {
                        state.selected.insert(name.clone());
                        if let ConnectionViewSelection::Tracks(set) =
                            &mut state.connection_view_selection
                        {
                            set.insert(name.clone());
                        } else {
                            let mut set = std::collections::HashSet::new();
                            set.insert(name.clone());
                            state.connection_view_selection = ConnectionViewSelection::Tracks(set);
                        }
                    } else {
                        state.last_selected_track = Some(name.clone());
                        state.selected.clear();
                        state.selected.insert(name.clone());
                        let mut set = std::collections::HashSet::new();
                        set.insert(name.clone());
                        state.connection_view_selection = ConnectionViewSelection::Tracks(set);
                    }
                } else if ctrl {
                    state.last_selected_track = Some(name.clone());
                    state.selected.insert(name.clone());
                    if let ConnectionViewSelection::Tracks(set) =
                        &mut state.connection_view_selection
                    {
                        set.insert(name.clone());
                    } else {
                        let mut set = std::collections::HashSet::new();
                        set.insert(name.clone());
                        state.connection_view_selection = ConnectionViewSelection::Tracks(set);
                    }
                } else {
                    state.last_selected_track = Some(name.clone());
                    state.selected.clear();
                    state.selected.insert(name.clone());
                    let mut set = std::collections::HashSet::new();
                    set.insert(name.clone());
                    state.connection_view_selection = ConnectionViewSelection::Tracks(set);
                }
                None
            }
            Message::SelectTrackFromMixer(ref name) => {
                let shift = self.state.blocking_read().shift;
                let ctrl = self.state.blocking_read().ctrl;
                let mut state = self.state.blocking_write();
                state.track_context_menu = None;
                state.connections_last_track_click = None;

                if shift {
                    let anchor = state
                        .last_selected_track
                        .as_ref()
                        .filter(|anchor| state.tracks.iter().any(|t| t.name == **anchor))
                        .cloned();
                    if let Some(anchor) = anchor {
                        if !ctrl {
                            state.selected.clear();
                            state.connection_view_selection = ConnectionViewSelection::None;
                        }
                        select_track_range(&mut state, &anchor, name);
                    } else if ctrl {
                        state.selected.insert(name.clone());
                        if let ConnectionViewSelection::Tracks(set) =
                            &mut state.connection_view_selection
                        {
                            set.insert(name.clone());
                        } else {
                            let mut set = std::collections::HashSet::new();
                            set.insert(name.clone());
                            state.connection_view_selection = ConnectionViewSelection::Tracks(set);
                        }
                    } else {
                        state.last_selected_track = Some(name.clone());
                        state.selected.clear();
                        state.selected.insert(name.clone());
                        let mut set = std::collections::HashSet::new();
                        set.insert(name.clone());
                        state.connection_view_selection = ConnectionViewSelection::Tracks(set);
                    }
                } else if ctrl {
                    state.last_selected_track = Some(name.clone());
                    state.selected.insert(name.clone());
                    if let ConnectionViewSelection::Tracks(set) =
                        &mut state.connection_view_selection
                    {
                        set.insert(name.clone());
                    } else {
                        let mut set = std::collections::HashSet::new();
                        set.insert(name.clone());
                        state.connection_view_selection = ConnectionViewSelection::Tracks(set);
                    }
                } else {
                    state.last_selected_track = Some(name.clone());
                    state.selected.clear();
                    state.selected.insert(name.clone());
                    let mut set = std::collections::HashSet::new();
                    set.insert(name.clone());
                    state.connection_view_selection = ConnectionViewSelection::Tracks(set);
                }
                None
            }
            _ => None,
        }
    }
}
