//! Sync-specific menu state and small sync menu dialogs.
//!
//! This module owns menu labels/enabled state derived from sync authentication
//! and the upload-conflict choice dialog. Long-running sync workflows belong in
//! `sync_actions` and sync runtime preparation belongs in `sync_runtime`.

use crate::CosimoUi;
use crate::app_config::{self, CONFIG_PATH, load_app_config};
use crate::file_ops::portable_path;
use crate::localization::Localizer;
use crate::menu_dispatch::DeferredMenuCommand;
use crate::menu_ui::set_menu_item_label;
use crate::review_ui::ReviewUi;
use crate::sync_runtime::SyncUploadConflict;
use crate::sync_runtime::sync_owner_and_token_for_config;
use wxdragon::id::{ID_NO, ID_YES};
use wxdragon::prelude::*;

const WX_CANCEL_DEFAULT_STYLE_BITS: i64 = 2_147_483_648;

#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum SyncAuthMenuAction {
    LogIn,
    LogOut,
}

impl SyncAuthMenuAction {
    pub(crate) fn command(self) -> DeferredMenuCommand {
        match self {
            Self::LogIn => DeferredMenuCommand::SyncLogin,
            Self::LogOut => DeferredMenuCommand::SyncLogout,
        }
    }

    fn label(self, localizer: Localizer) -> &'static str {
        match self {
            Self::LogIn => localizer.sync_login_menu_item(),
            Self::LogOut => localizer.sync_logout_menu_item(),
        }
    }
}

pub(crate) fn sync_auth_menu_action_for_config(
    config: &app_config::AppConfig,
) -> SyncAuthMenuAction {
    if config.sync_server_url.is_some() && sync_owner_and_token_for_config(config).is_some() {
        SyncAuthMenuAction::LogOut
    } else {
        SyncAuthMenuAction::LogIn
    }
}

pub(crate) fn current_sync_auth_menu_action() -> SyncAuthMenuAction {
    load_app_config(portable_path(CONFIG_PATH))
        .map(|config| sync_auth_menu_action_for_config(&config))
        .unwrap_or(SyncAuthMenuAction::LogIn)
}

pub(crate) fn sync_auth_menu_state(ui: &ReviewUi, localizer: Localizer) {
    let action = current_sync_auth_menu_action();
    let server_configured = load_app_config(portable_path(CONFIG_PATH))
        .ok()
        .and_then(|config| config.sync_server_url)
        .is_some_and(|url| !url.trim().is_empty());
    if let Some(menu_bar) = ui.frame.get_menu_bar() {
        set_menu_item_label(
            &menu_bar,
            CosimoUi::xrc_id("menu_sync_auth"),
            action.label(localizer),
        );
        let authenticated = action == SyncAuthMenuAction::LogOut;
        menu_bar.enable_item(
            CosimoUi::xrc_id("menu_sync_register_account"),
            server_configured && !authenticated,
        );
        menu_bar.enable_item(
            CosimoUi::xrc_id("menu_sync_invalidate_token"),
            authenticated,
        );
        menu_bar.enable_item(
            CosimoUi::xrc_id("menu_sync_invalidate_all_tokens"),
            authenticated,
        );
        menu_bar.enable_item(
            CosimoUi::xrc_id("menu_sync_delete_account"),
            server_configured,
        );
    }
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub(crate) enum SyncUploadConflictChoice {
    ForceUpload,
    DownloadInstead,
    Cancel,
}

pub(crate) fn show_sync_upload_conflict_dialog(
    parent: &dyn WxWidget,
    localizer: Localizer,
    conflict: &SyncUploadConflict,
) -> SyncUploadConflictChoice {
    let dialog = MessageDialog::builder(
        parent,
        &localizer.sync_upload_conflict_message(
            conflict.local_expected_revision.as_deref(),
            conflict.remote_revision.as_deref(),
        ),
        localizer.sync_upload_conflict_caption(),
    )
    .with_style(sync_upload_conflict_dialog_style())
    .build();
    match dialog.show_modal() {
        ID_YES => SyncUploadConflictChoice::ForceUpload,
        ID_NO => SyncUploadConflictChoice::DownloadInstead,
        _ => SyncUploadConflictChoice::Cancel,
    }
}

fn sync_upload_conflict_dialog_style() -> MessageDialogStyle {
    MessageDialogStyle::YesNo
        | MessageDialogStyle::Cancel
        | MessageDialogStyle::IconWarning
        | MessageDialogStyle::from_bits_retain(WX_CANCEL_DEFAULT_STYLE_BITS)
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn sync_upload_conflict_dialog_defaults_to_cancel() {
        assert!(sync_upload_conflict_dialog_style().bits() & WX_CANCEL_DEFAULT_STYLE_BITS != 0);
    }
}
