use std::path::{Path, PathBuf};

use crate::app_config::{AppConfig, MAX_RECENT_DECKS};
use crate::localization::Localizer;
use crate::menu_dispatch::RecentDeckSlot;

#[derive(Clone, Copy)]
pub(crate) enum TopLevelMenu {
    File,
    Deck,
    Cards,
    Study,
    Tools,
    View,
    Help,
}

impl TopLevelMenu {
    pub(crate) fn position(self) -> usize {
        match self {
            TopLevelMenu::File => 0,
            TopLevelMenu::Deck => 1,
            TopLevelMenu::Cards => 2,
            TopLevelMenu::Study => 3,
            TopLevelMenu::Tools => 4,
            TopLevelMenu::View => 5,
            TopLevelMenu::Help => 6,
        }
    }
}

pub(crate) struct TopLevelMenuLabel {
    pub(crate) menu: TopLevelMenu,
    pub(crate) label: &'static str,
}

pub(crate) struct MenuItemLabel {
    #[cfg_attr(not(test), allow(dead_code))]
    pub(crate) menu_xrc_name: &'static str,
    pub(crate) xrc_name: &'static str,
    pub(crate) label: &'static str,
}

pub(crate) struct SubmenuLabel {
    #[cfg_attr(not(test), allow(dead_code))]
    pub(crate) menu_xrc_name: &'static str,
    pub(crate) xrc_name: &'static str,
    pub(crate) label: &'static str,
}

pub(crate) fn localized_top_level_menu_labels(localizer: Localizer) -> Vec<TopLevelMenuLabel> {
    vec![
        TopLevelMenuLabel {
            menu: TopLevelMenu::File,
            label: localizer.file_menu(),
        },
        TopLevelMenuLabel {
            menu: TopLevelMenu::Deck,
            label: localizer.deck_menu(),
        },
        TopLevelMenuLabel {
            menu: TopLevelMenu::Cards,
            label: localizer.cards_menu(),
        },
        TopLevelMenuLabel {
            menu: TopLevelMenu::Study,
            label: localizer.study_menu(),
        },
        TopLevelMenuLabel {
            menu: TopLevelMenu::Tools,
            label: localizer.tools_menu(),
        },
        TopLevelMenuLabel {
            menu: TopLevelMenu::View,
            label: localizer.view_menu(),
        },
        TopLevelMenuLabel {
            menu: TopLevelMenu::Help,
            label: localizer.help_menu(),
        },
    ]
}

pub(crate) fn localized_menu_item_labels(localizer: Localizer) -> Vec<MenuItemLabel> {
    fn item(
        menu_xrc_name: &'static str,
        xrc_name: &'static str,
        label: &'static str,
    ) -> MenuItemLabel {
        MenuItemLabel {
            menu_xrc_name,
            xrc_name,
            label,
        }
    }

    vec![
        item(
            "menu_file",
            "menu_open_deck",
            localizer.open_deck_menu_item(),
        ),
        item(
            "menu_file",
            "menu_import_anki_deck",
            localizer.import_anki_deck_menu_item(),
        ),
        item("menu_tools", "menu_options", localizer.options_menu_item()),
        item(
            "menu_deck",
            "menu_deck_properties",
            localizer.deck_properties_menu_item(),
        ),
        item(
            "menu_deck",
            "menu_edit_deck_properties",
            localizer.edit_deck_properties_menu_item(),
        ),
        item(
            "menu_sync",
            "menu_sync_status",
            localizer.sync_status_menu_item(),
        ),
        item(
            "menu_sync",
            "menu_sync_remote_decks",
            localizer.sync_remote_decks_menu_item(),
        ),
        item(
            "menu_sync",
            "menu_sync_auth",
            localizer.sync_login_menu_item(),
        ),
        item(
            "menu_sync",
            "menu_sync_register_account",
            localizer.sync_register_account_menu_item(),
        ),
        item(
            "menu_sync",
            "menu_sync_invalidate_token",
            localizer.sync_invalidate_token_menu_item(),
        ),
        item(
            "menu_sync",
            "menu_sync_invalidate_all_tokens",
            localizer.sync_invalidate_all_tokens_menu_item(),
        ),
        item(
            "menu_sync",
            "menu_sync_delete_account",
            localizer.sync_delete_account_menu_item(),
        ),
        item(
            "menu_sync",
            "menu_sync_upload",
            localizer.sync_upload_menu_item(),
        ),
        item(
            "menu_sync",
            "menu_sync_download",
            localizer.sync_download_menu_item(),
        ),
        item(
            "menu_study",
            "menu_learning_dashboard",
            localizer.learning_dashboard_menu_item(),
        ),
        item(
            "menu_study",
            "menu_start_scheduled",
            localizer.start_scheduled_menu_item(),
        ),
        item(
            "menu_study",
            "menu_force_start",
            localizer.force_start_menu_item(),
        ),
        item(
            "menu_study",
            "menu_start_exam",
            localizer.start_exam_menu_item(),
        ),
        item(
            "menu_study",
            "menu_start_quiz",
            localizer.start_quiz_menu_item(),
        ),
        item(
            "menu_tools",
            "menu_generate_audio",
            localizer.generate_audio_menu_item(),
        ),
        item(
            "menu_tools",
            "menu_remove_inoperative_audio",
            localizer.remove_inoperative_audio_menu_item(),
        ),
        item(
            "menu_file",
            "menu_export_deck_bundle",
            localizer.export_deck_bundle_menu_item(),
        ),
        item(
            "menu_file",
            "menu_export_deck_bundle_with_study_history",
            localizer.export_deck_bundle_with_study_history_menu_item(),
        ),
        item(
            "menu_file",
            "menu_write_deck_bundle_backup",
            localizer.write_deck_bundle_backup_menu_item(),
        ),
        item(
            "menu_file",
            "menu_restore_deck_bundle",
            localizer.restore_deck_bundle_menu_item(),
        ),
        item(
            "menu_tools",
            "menu_scrub_review_database",
            localizer.scrub_review_database_menu_item(),
        ),
        item(
            "menu_tools",
            "menu_reclaim_database_space",
            localizer.reclaim_database_space_menu_item(),
        ),
        item(
            "menu_tools",
            "menu_prune_backups",
            localizer.prune_backups_menu_item(),
        ),
        item(
            "menu_tools",
            "menu_wipe_backup_directory",
            localizer.wipe_backup_directory_menu_item(),
        ),
        item("menu_file", "menu_quit", localizer.quit_menu_item()),
        item(
            "menu_cards",
            "menu_add_card",
            localizer.add_card_menu_item(),
        ),
        item(
            "menu_cards",
            "menu_add_card_batch",
            localizer.add_card_batch_menu_item(),
        ),
        item(
            "menu_cards",
            "menu_edit_card",
            localizer.edit_selected_card_menu_item(),
        ),
        item(
            "menu_cards",
            "menu_remove_card",
            localizer.remove_selected_card_menu_item(),
        ),
        item(
            "menu_cards",
            "menu_card_details",
            localizer.selected_card_details_menu_item(),
        ),
        item(
            "menu_deck",
            "menu_resolve_duplicate_prompts",
            localizer.resolve_duplicate_prompts_menu_item(),
        ),
        item(
            "menu_cards",
            "menu_toggle_card_flag",
            localizer.flag_selected_card_menu_item(),
        ),
        item(
            "menu_cards",
            "menu_toggle_card_suspension",
            localizer.suspend_selected_card_menu_item(),
        ),
        item(
            "menu_cards",
            "menu_toggle_card_deferral",
            localizer.defer_selected_card_until_tomorrow_menu_item(),
        ),
        item(
            "menu_cards",
            "menu_flag_all_shown_cards",
            localizer.flag_all_shown_cards_menu_item(),
        ),
        item(
            "menu_cards",
            "menu_unflag_all_shown_cards",
            localizer.unflag_all_shown_cards_menu_item(),
        ),
        item(
            "menu_cards",
            "menu_suspend_all_shown_cards",
            localizer.suspend_all_shown_cards_menu_item(),
        ),
        item(
            "menu_cards",
            "menu_unsuspend_all_shown_cards",
            localizer.unsuspend_all_shown_cards_menu_item(),
        ),
        item(
            "menu_study",
            "menu_review_flagged_cards",
            localizer.review_flagged_cards_menu_item(),
        ),
        item(
            "menu_cards",
            "menu_toggle_card_reversal",
            localizer.make_selected_card_reversible_menu_item(),
        ),
        item(
            "menu_cards",
            "menu_toggle_card_reversal_exclusion",
            localizer.mark_selected_card_non_reversible_menu_item(),
        ),
        item(
            "menu_deck",
            "menu_make_eligible_cards_reversible",
            localizer.make_eligible_cards_reversible_menu_item(),
        ),
        item(
            "menu_deck",
            "menu_undo_last_bulk_reversal",
            localizer.undo_last_bulk_reversal_menu_item(),
        ),
        item(
            "menu_view",
            "menu_sort_deck_order",
            localizer.sort_deck_order_menu_item(),
        ),
        item(
            "menu_view",
            "menu_sort_next_scheduled",
            localizer.sort_next_scheduled_menu_item(),
        ),
        item(
            "menu_view",
            "menu_sort_last_reviewed",
            localizer.sort_last_reviewed_menu_item(),
        ),
        item(
            "menu_view",
            "menu_sort_prompt_text",
            localizer.sort_prompt_text_menu_item(),
        ),
        item(
            "menu_view",
            "menu_sort_response_text",
            localizer.sort_response_text_menu_item(),
        ),
        item(
            "menu_view",
            "menu_sort_estimated_recall",
            localizer.sort_estimated_recall_menu_item(),
        ),
        item(
            "menu_view",
            "menu_sort_ascending",
            localizer.sort_ascending_menu_item(),
        ),
        item(
            "menu_view",
            "menu_sort_descending",
            localizer.sort_descending_menu_item(),
        ),
        item(
            "menu_help",
            "menu_user_guide",
            localizer.user_guide_menu_item(),
        ),
        item(
            "menu_help",
            "menu_report_bug",
            localizer.report_bug_menu_item(),
        ),
        item(
            "menu_help",
            "menu_project_wiki",
            localizer.project_wiki_menu_item(),
        ),
        item("menu_help", "menu_about", localizer.about_menu_item()),
    ]
}

pub(crate) fn localized_submenu_labels(localizer: Localizer) -> Vec<SubmenuLabel> {
    vec![
        SubmenuLabel {
            menu_xrc_name: "menu_file",
            xrc_name: "menu_recent_decks",
            label: localizer.recent_decks_menu_item(),
        },
        SubmenuLabel {
            menu_xrc_name: "menu_deck",
            xrc_name: "menu_sync",
            label: localizer.sync_submenu_item(),
        },
    ]
}

pub(crate) fn recent_deck_menu_item_names() -> [&'static str; MAX_RECENT_DECKS] {
    [
        "menu_recent_deck_1",
        "menu_recent_deck_2",
        "menu_recent_deck_3",
        "menu_recent_deck_4",
        "menu_recent_deck_5",
        "menu_recent_deck_6",
        "menu_recent_deck_7",
        "menu_recent_deck_8",
    ]
}

#[derive(Debug, PartialEq, Eq)]
pub(crate) enum RecentDeckMenuSlot {
    Show(String),
    Hide,
}

#[derive(Debug, PartialEq, Eq)]
pub(crate) enum RecentDeckMenuLayout {
    Hidden,
    DirectItem(String),
    Submenu([RecentDeckMenuSlot; MAX_RECENT_DECKS]),
}

pub(crate) fn recent_deck_menu_slots(
    recent_deck_paths: &[PathBuf],
) -> [RecentDeckMenuSlot; MAX_RECENT_DECKS] {
    std::array::from_fn(|index| {
        recent_deck_paths
            .get(index)
            .map(|deck_path| {
                let slot = RecentDeckSlot::new(index).expect("recent deck menu slot index");
                RecentDeckMenuSlot::Show(recent_deck_menu_item_label(slot, deck_path))
            })
            .unwrap_or(RecentDeckMenuSlot::Hide)
    })
}

pub(crate) fn recent_deck_menu_layout(recent_deck_paths: &[PathBuf]) -> RecentDeckMenuLayout {
    match recent_deck_paths {
        [] => RecentDeckMenuLayout::Hidden,
        [deck_path] => {
            RecentDeckMenuLayout::DirectItem(single_recent_deck_menu_item_label(deck_path))
        }
        _ => RecentDeckMenuLayout::Submenu(recent_deck_menu_slots(recent_deck_paths)),
    }
}

pub(crate) fn recent_deck_paths_for_menu(
    config: &AppConfig,
    current_deck_path: Option<&Path>,
) -> Vec<PathBuf> {
    let current_deck_path = current_deck_path.or(config.last_open_deck_path.as_deref());
    config
        .recent_deck_paths
        .iter()
        .filter(|deck_path| Some(deck_path.as_path()) != current_deck_path)
        .cloned()
        .collect()
}

pub(crate) fn single_recent_deck_menu_item_label(deck_path: &Path) -> String {
    deck_path.display().to_string().replace('&', "&&")
}

pub(crate) fn recent_deck_menu_item_label(slot: RecentDeckSlot, deck_path: &Path) -> String {
    format!(
        "{}. {}",
        slot.display_number(),
        deck_path.display().to_string().replace('&', "&&")
    )
}
