#[cfg(test)]
mod tests {
  use crate::app::App;
  use crate::app::key_binding::DEFAULT_KEYBINDINGS;
  use crate::assert_navigation_pushed;
  use crate::handlers::KeyEventHandler;
  use crate::handlers::sonarr_handlers::SonarrHandler;
  use crate::handlers::sonarr_handlers::handle_change_tab_left_right_keys;
  use crate::models::servarr_data::sonarr::sonarr_data::ActiveSonarrBlock;
  use crate::test_handler_delegation;
  use pretty_assertions::assert_eq;
  use rstest::rstest;
  use strum::IntoEnumIterator;

  #[rstest]
  #[case(0, ActiveSonarrBlock::System, ActiveSonarrBlock::Downloads)]
  #[case(1, ActiveSonarrBlock::Series, ActiveSonarrBlock::Blocklist)]
  #[case(2, ActiveSonarrBlock::Downloads, ActiveSonarrBlock::History)]
  #[case(3, ActiveSonarrBlock::Blocklist, ActiveSonarrBlock::RootFolders)]
  #[case(4, ActiveSonarrBlock::History, ActiveSonarrBlock::Indexers)]
  #[case(5, ActiveSonarrBlock::RootFolders, ActiveSonarrBlock::System)]
  #[case(6, ActiveSonarrBlock::Indexers, ActiveSonarrBlock::Series)]
  fn test_sonarr_handler_change_tab_left_right_keys(
    #[case] index: usize,
    #[case] left_block: ActiveSonarrBlock,
    #[case] right_block: ActiveSonarrBlock,
  ) {
    let mut app = App::test_default();
    app.data.sonarr_data.main_tabs.set_index(index);

    handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.left.key);

    assert_eq!(
      app.data.sonarr_data.main_tabs.get_active_route(),
      left_block.into()
    );
    assert_navigation_pushed!(app, left_block.into());

    app.data.sonarr_data.main_tabs.set_index(index);

    handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.right.key);

    assert_eq!(
      app.data.sonarr_data.main_tabs.get_active_route(),
      right_block.into()
    );
    assert_navigation_pushed!(app, right_block.into());
  }

  #[rstest]
  #[case(0, ActiveSonarrBlock::System, ActiveSonarrBlock::Downloads)]
  #[case(1, ActiveSonarrBlock::Series, ActiveSonarrBlock::Blocklist)]
  #[case(2, ActiveSonarrBlock::Downloads, ActiveSonarrBlock::History)]
  #[case(3, ActiveSonarrBlock::Blocklist, ActiveSonarrBlock::RootFolders)]
  #[case(4, ActiveSonarrBlock::History, ActiveSonarrBlock::Indexers)]
  #[case(5, ActiveSonarrBlock::RootFolders, ActiveSonarrBlock::System)]
  #[case(6, ActiveSonarrBlock::Indexers, ActiveSonarrBlock::Series)]
  fn test_sonarr_handler_change_tab_left_right_keys_alt_navigation(
    #[case] index: usize,
    #[case] left_block: ActiveSonarrBlock,
    #[case] right_block: ActiveSonarrBlock,
  ) {
    let mut app = App::test_default();
    app.data.sonarr_data.main_tabs.set_index(index);

    handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.left.alt.unwrap());

    assert_eq!(
      app.data.sonarr_data.main_tabs.get_active_route(),
      left_block.into()
    );
    assert_navigation_pushed!(app, left_block.into());

    app.data.sonarr_data.main_tabs.set_index(index);

    handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.right.alt.unwrap());

    assert_eq!(
      app.data.sonarr_data.main_tabs.get_active_route(),
      right_block.into()
    );
    assert_navigation_pushed!(app, right_block.into());
  }

  #[rstest]
  #[case(0, ActiveSonarrBlock::Series)]
  #[case(1, ActiveSonarrBlock::Downloads)]
  #[case(2, ActiveSonarrBlock::Blocklist)]
  #[case(3, ActiveSonarrBlock::History)]
  #[case(4, ActiveSonarrBlock::RootFolders)]
  #[case(5, ActiveSonarrBlock::Indexers)]
  #[case(6, ActiveSonarrBlock::System)]
  fn test_sonarr_handler_change_tab_left_right_keys_alt_navigation_no_op_when_ignoring_quit_key(
    #[case] index: usize,
    #[case] block: ActiveSonarrBlock,
  ) {
    let mut app = App::test_default();
    app.push_navigation_stack(block.into());
    app.ignore_special_keys_for_textbox_input = true;
    app.data.sonarr_data.main_tabs.set_index(index);

    handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.left.alt.unwrap());

    assert_eq!(
      app.data.sonarr_data.main_tabs.get_active_route(),
      block.into()
    );
    assert_eq!(app.get_current_route(), block.into());

    app.data.sonarr_data.main_tabs.set_index(index);

    handle_change_tab_left_right_keys(&mut app, DEFAULT_KEYBINDINGS.right.alt.unwrap());

    assert_eq!(
      app.data.sonarr_data.main_tabs.get_active_route(),
      block.into()
    );
    assert_eq!(app.get_current_route(), block.into());
  }

  #[rstest]
  fn test_delegates_library_blocks_to_library_handler(
    #[values(
      ActiveSonarrBlock::AddSeriesAlreadyInLibrary,
      ActiveSonarrBlock::AddSeriesEmptySearchResults,
      ActiveSonarrBlock::AddSeriesPrompt,
      ActiveSonarrBlock::AddSeriesSearchInput,
      ActiveSonarrBlock::AddSeriesSearchResults,
      ActiveSonarrBlock::AddSeriesSelectLanguageProfile,
      ActiveSonarrBlock::AddSeriesSelectMonitor,
      ActiveSonarrBlock::AddSeriesSelectQualityProfile,
      ActiveSonarrBlock::AddSeriesSelectRootFolder,
      ActiveSonarrBlock::AddSeriesSelectSeriesType,
      ActiveSonarrBlock::AddSeriesTagsInput,
      ActiveSonarrBlock::AutomaticallySearchEpisodePrompt,
      ActiveSonarrBlock::AutomaticallySearchSeasonPrompt,
      ActiveSonarrBlock::AutomaticallySearchSeriesPrompt,
      ActiveSonarrBlock::DeleteEpisodeFilePrompt,
      ActiveSonarrBlock::DeleteSeriesPrompt,
      ActiveSonarrBlock::EditSeriesPrompt,
      ActiveSonarrBlock::EditSeriesPathInput,
      ActiveSonarrBlock::EditSeriesSelectSeriesType,
      ActiveSonarrBlock::EditSeriesSelectQualityProfile,
      ActiveSonarrBlock::EditSeriesSelectLanguageProfile,
      ActiveSonarrBlock::EditSeriesTagsInput,
      ActiveSonarrBlock::EpisodeDetails,
      ActiveSonarrBlock::EpisodeFile,
      ActiveSonarrBlock::EpisodeHistory,
      ActiveSonarrBlock::FilterSeries,
      ActiveSonarrBlock::FilterSeriesError,
      ActiveSonarrBlock::FilterSeriesHistory,
      ActiveSonarrBlock::FilterSeriesHistoryError,
      ActiveSonarrBlock::ManualEpisodeSearch,
      ActiveSonarrBlock::ManualEpisodeSearchConfirmPrompt,
      ActiveSonarrBlock::ManualEpisodeSearchSortPrompt,
      ActiveSonarrBlock::ManualSeasonSearch,
      ActiveSonarrBlock::ManualSeasonSearchConfirmPrompt,
      ActiveSonarrBlock::ManualSeasonSearchSortPrompt,
      ActiveSonarrBlock::SearchEpisodes,
      ActiveSonarrBlock::SearchEpisodesError,
      ActiveSonarrBlock::SearchSeason,
      ActiveSonarrBlock::SearchSeasonError,
      ActiveSonarrBlock::SearchSeries,
      ActiveSonarrBlock::SearchSeriesError,
      ActiveSonarrBlock::SearchSeriesHistory,
      ActiveSonarrBlock::SearchSeriesHistoryError,
      ActiveSonarrBlock::SeasonDetails,
      ActiveSonarrBlock::Series,
      ActiveSonarrBlock::SeriesDetails,
      ActiveSonarrBlock::SeriesHistory,
      ActiveSonarrBlock::SeriesHistorySortPrompt,
      ActiveSonarrBlock::SeriesSortPrompt,
      ActiveSonarrBlock::UpdateAllSeriesPrompt,
      ActiveSonarrBlock::UpdateAndScanSeriesPrompt,
      ActiveSonarrBlock::SeriesHistoryDetails
    )]
    active_sonarr_block: ActiveSonarrBlock,
  ) {
    test_handler_delegation!(
      SonarrHandler,
      ActiveSonarrBlock::Series,
      active_sonarr_block
    );
  }

  #[rstest]
  fn test_delegates_downloads_blocks_to_downloads_handler(
    #[values(
      ActiveSonarrBlock::Downloads,
      ActiveSonarrBlock::DeleteDownloadPrompt,
      ActiveSonarrBlock::UpdateDownloadsPrompt
    )]
    active_sonarr_block: ActiveSonarrBlock,
  ) {
    test_handler_delegation!(
      SonarrHandler,
      ActiveSonarrBlock::Downloads,
      active_sonarr_block
    );
  }

  #[rstest]
  fn test_delegates_blocklist_blocks_to_blocklist_handler(
    #[values(
      ActiveSonarrBlock::Blocklist,
      ActiveSonarrBlock::BlocklistItemDetails,
      ActiveSonarrBlock::DeleteBlocklistItemPrompt,
      ActiveSonarrBlock::BlocklistClearAllItemsPrompt,
      ActiveSonarrBlock::BlocklistSortPrompt
    )]
    active_sonarr_block: ActiveSonarrBlock,
  ) {
    test_handler_delegation!(
      SonarrHandler,
      ActiveSonarrBlock::Blocklist,
      active_sonarr_block
    );
  }

  #[rstest]
  fn test_delegates_history_blocks_to_history_handler(
    #[values(
      ActiveSonarrBlock::History,
      ActiveSonarrBlock::HistoryItemDetails,
      ActiveSonarrBlock::HistorySortPrompt,
      ActiveSonarrBlock::FilterHistory,
      ActiveSonarrBlock::FilterHistoryError,
      ActiveSonarrBlock::SearchHistory,
      ActiveSonarrBlock::SearchHistoryError
    )]
    active_sonarr_block: ActiveSonarrBlock,
  ) {
    test_handler_delegation!(
      SonarrHandler,
      ActiveSonarrBlock::History,
      active_sonarr_block
    );
  }

  #[rstest]
  fn test_delegates_root_folders_blocks_to_root_folders_handler(
    #[values(
      ActiveSonarrBlock::RootFolders,
      ActiveSonarrBlock::AddRootFolderPrompt,
      ActiveSonarrBlock::DeleteRootFolderPrompt
    )]
    active_sonarr_block: ActiveSonarrBlock,
  ) {
    test_handler_delegation!(
      SonarrHandler,
      ActiveSonarrBlock::RootFolders,
      active_sonarr_block
    );
  }

  #[rstest]
  fn test_delegates_indexers_blocks_to_indexers_handler(
    #[values(
      ActiveSonarrBlock::DeleteIndexerPrompt,
      ActiveSonarrBlock::Indexers,
      ActiveSonarrBlock::AllIndexerSettingsPrompt,
      ActiveSonarrBlock::IndexerSettingsConfirmPrompt,
      ActiveSonarrBlock::IndexerSettingsMaximumSizeInput,
      ActiveSonarrBlock::IndexerSettingsMinimumAgeInput,
      ActiveSonarrBlock::IndexerSettingsRetentionInput,
      ActiveSonarrBlock::IndexerSettingsRssSyncIntervalInput
    )]
    active_sonarr_block: ActiveSonarrBlock,
  ) {
    test_handler_delegation!(
      SonarrHandler,
      ActiveSonarrBlock::Indexers,
      active_sonarr_block
    );
  }

  #[rstest]
  fn test_delegates_system_blocks_to_system_handler(
    #[values(
      ActiveSonarrBlock::System,
      ActiveSonarrBlock::SystemLogs,
      ActiveSonarrBlock::SystemQueuedEvents,
      ActiveSonarrBlock::SystemTasks,
      ActiveSonarrBlock::SystemTaskStartConfirmPrompt,
      ActiveSonarrBlock::SystemUpdates
    )]
    active_sonarr_block: ActiveSonarrBlock,
  ) {
    test_handler_delegation!(
      SonarrHandler,
      ActiveSonarrBlock::System,
      active_sonarr_block
    );
  }

  #[test]
  fn test_sonarr_handler_accepts() {
    ActiveSonarrBlock::iter().for_each(|active_sonarr_block| {
      assert!(SonarrHandler::accepts(active_sonarr_block));
    })
  }

  #[rstest]
  fn test_sonarr_handler_ignore_special_keys(
    #[values(true, false)] ignore_special_keys_for_textbox_input: bool,
  ) {
    let mut app = App::test_default();
    app.ignore_special_keys_for_textbox_input = ignore_special_keys_for_textbox_input;
    let handler = SonarrHandler::new(
      DEFAULT_KEYBINDINGS.esc.key,
      &mut app,
      ActiveSonarrBlock::default(),
      None,
    );

    assert_eq!(
      handler.ignore_special_keys(),
      ignore_special_keys_for_textbox_input
    );
  }

  #[test]
  fn test_sonarr_handler_is_ready() {
    let mut app = App::test_default();
    app.is_loading = true;

    let handler = SonarrHandler::new(
      DEFAULT_KEYBINDINGS.esc.key,
      &mut app,
      ActiveSonarrBlock::default(),
      None,
    );

    assert!(handler.is_ready());
  }
}
