use super::common_key_events;
use crate::{
  core::app::{ActiveBlock, App},
  core::source::Source,
  tui::event::Key,
};

// When no block is actively selected, just handle regular event
pub fn handler(key: Key, app: &mut App) {
  match key {
    Key::Enter => {
      let current_hovered = app.get_current_route().hovered_block;
      app.set_current_route_state(Some(current_hovered), None);
    }
    k if common_key_events::down_event(k, &app.user_config.keys) => {
      match app.get_current_route().hovered_block {
        ActiveBlock::Library => {
          app.set_current_route_state(None, Some(ActiveBlock::MyPlaylists));
        }
        ActiveBlock::ArtistBlock
        | ActiveBlock::AlbumList
        | ActiveBlock::AlbumTracks
        | ActiveBlock::Artists
        | ActiveBlock::Podcasts
        | ActiveBlock::EpisodeTable
        | ActiveBlock::Home
        | ActiveBlock::Discover
        | ActiveBlock::MyPlaylists
        | ActiveBlock::RecentlyPlayed
        | ActiveBlock::TrackTable => {
          app.set_current_route_state(None, Some(ActiveBlock::PlayBar));
        }
        _ => {}
      }
    }
    k if common_key_events::up_event(k, &app.user_config.keys) => {
      match app.get_current_route().hovered_block {
        // Under any non-Spotify source (Local, Subsonic) the Library list is
        // hidden, so MyPlaylists is already the top sidebar block — pressing up
        // should stay put rather than jump to a block that isn't rendered.
        ActiveBlock::MyPlaylists if app.active_source == Source::Spotify => {
          app.set_current_route_state(None, Some(ActiveBlock::Library));
        }
        ActiveBlock::PlayBar => {
          app.set_current_route_state(None, Some(ActiveBlock::MyPlaylists));
        }
        _ => {}
      }
    }
    k if common_key_events::left_event(k, &app.user_config.keys) => {
      match app.get_current_route().hovered_block {
        ActiveBlock::ArtistBlock
        | ActiveBlock::AlbumList
        | ActiveBlock::AlbumTracks
        | ActiveBlock::Artists
        | ActiveBlock::Podcasts
        | ActiveBlock::EpisodeTable
        | ActiveBlock::Home
        | ActiveBlock::Discover
        | ActiveBlock::RecentlyPlayed
        | ActiveBlock::TrackTable => {
          let top = common_key_events::sidebar_top_block(app);
          app.set_current_route_state(None, Some(top));
        }
        _ => {}
      }
    }
    k if common_key_events::right_event(k, &app.user_config.keys) => {
      common_key_events::handle_right_event(app)
    }
    Key::Char('w') if app.get_current_route().hovered_block == ActiveBlock::PlayBar => {
      super::playbar::handler(key, app);
    }
    _ => (),
  };
}

#[cfg(test)]
mod tests {
  use super::*;
  use crate::core::app::RouteId;

  #[test]
  fn on_enter() {
    let mut app = App::default();

    app.set_current_route_state(Some(ActiveBlock::Empty), Some(ActiveBlock::Library));

    handler(Key::Enter, &mut app);
    let current_route = app.get_current_route();

    assert_eq!(current_route.active_block, ActiveBlock::Library);
    assert_eq!(current_route.hovered_block, ActiveBlock::Library);
  }

  #[test]
  fn on_down_press() {
    let mut app = App::default();

    app.set_current_route_state(Some(ActiveBlock::Empty), Some(ActiveBlock::Library));

    handler(Key::Down, &mut app);
    let current_route = app.get_current_route();

    assert_eq!(current_route.active_block, ActiveBlock::Empty);
    assert_eq!(current_route.hovered_block, ActiveBlock::MyPlaylists);

    // TODO: test the other cases when they are implemented
  }

  #[test]
  fn on_up_press() {
    let mut app = App::default();

    app.set_current_route_state(Some(ActiveBlock::Empty), Some(ActiveBlock::MyPlaylists));

    handler(Key::Up, &mut app);
    let current_route = app.get_current_route();

    assert_eq!(current_route.active_block, ActiveBlock::Empty);
    assert_eq!(current_route.hovered_block, ActiveBlock::Library);
  }

  #[test]
  fn on_left_press() {
    let mut app = App::default();
    app.set_current_route_state(Some(ActiveBlock::Empty), Some(ActiveBlock::AlbumTracks));

    handler(Key::Left, &mut app);
    let current_route = app.get_current_route();
    assert_eq!(current_route.active_block, ActiveBlock::Empty);
    assert_eq!(current_route.hovered_block, ActiveBlock::Library);

    app.set_current_route_state(None, Some(ActiveBlock::Home));
    handler(Key::Left, &mut app);
    let current_route = app.get_current_route();
    assert_eq!(current_route.hovered_block, ActiveBlock::Library);

    app.set_current_route_state(None, Some(ActiveBlock::TrackTable));
    handler(Key::Left, &mut app);
    let current_route = app.get_current_route();
    assert_eq!(current_route.hovered_block, ActiveBlock::Library);
  }

  #[test]
  fn on_right_press() {
    let mut app = App::default();

    app.set_current_route_state(Some(ActiveBlock::Empty), Some(ActiveBlock::Library));
    app.push_navigation_stack(RouteId::AlbumTracks, ActiveBlock::AlbumTracks);
    handler(Key::Right, &mut app);
    let current_route = app.get_current_route();

    assert_eq!(current_route.active_block, ActiveBlock::AlbumTracks);
    assert_eq!(current_route.hovered_block, ActiveBlock::AlbumTracks);

    app.push_navigation_stack(RouteId::Search, ActiveBlock::Empty);
    app.set_current_route_state(None, Some(ActiveBlock::MyPlaylists));
    handler(Key::Right, &mut app);
    let current_route = app.get_current_route();

    assert_eq!(current_route.active_block, ActiveBlock::SearchResultBlock);
    assert_eq!(current_route.hovered_block, ActiveBlock::SearchResultBlock);

    app.set_current_route_state(None, Some(ActiveBlock::Library));
    app.push_navigation_stack(RouteId::TrackTable, ActiveBlock::TrackTable);
    handler(Key::Right, &mut app);
    let current_route = app.get_current_route();

    assert_eq!(current_route.active_block, ActiveBlock::TrackTable);
    assert_eq!(current_route.hovered_block, ActiveBlock::TrackTable);

    app.set_current_route_state(None, Some(ActiveBlock::Library));
    app.push_navigation_stack(RouteId::TrackTable, ActiveBlock::TrackTable);
    handler(Key::Right, &mut app);
    let current_route = app.get_current_route();
    assert_eq!(current_route.active_block, ActiveBlock::TrackTable);
    assert_eq!(current_route.hovered_block, ActiveBlock::TrackTable);

    app.push_navigation_stack(RouteId::Home, ActiveBlock::Home);
    app.set_current_route_state(Some(ActiveBlock::Empty), Some(ActiveBlock::Library));
    handler(Key::Right, &mut app);
    let current_route = app.get_current_route();
    assert_eq!(current_route.active_block, ActiveBlock::Home);
    assert_eq!(current_route.hovered_block, ActiveBlock::Home);
  }

  #[test]
  fn on_w_press_over_playbar_adds_current_track() {
    let mut app = App::default();
    app.set_current_route_state(Some(ActiveBlock::Empty), Some(ActiveBlock::PlayBar));

    handler(Key::Char('w'), &mut app);

    assert_eq!(
      app.status_message.as_deref(),
      Some("No track currently playing")
    );
  }
}
