use super::*;
use crate::util::telegram_stars::*;

#[derive(BotCommands, Clone)]
#[command(rename_rule = "snake_case")]
enum Command {
    Clear
}

pub fn schema() -> UpdateHandler<Box<dyn std::error::Error + Send + Sync + 'static>> {
    let map_profile = |update: Update, dialogue: MasterDialogue| async move {
            if let Some(chat) = update.chat() {
                match dialogue.get_or_fetch_profile(chat.id.0).await {
                    Ok(profile) => profile,
                    Err(e) => {
                        log::warn!("Failed to get profile for user {}: {}", chat.id.0, e);
                        Profile::default()
                    }
                }
            } else {
                log::warn!("Update have no chat");
                Profile::default()
            }
        };

    let map_settings = |profile: Profile| async move {
            HandlerSettings {
                behavior: ForceHandlerBehavior::None,
                language: profile.language,
            }
        };

    let clear_state = Update::filter_message().filter_command::<Command>().branch(case![Command::Clear].endpoint(clear_state));

    let entrypoints = dptree::entry()
        .branch(
            admin::admin_filter_async()
            .chain(
                Update::filter_message().filter_command::<admin::Command>()
                .branch(case![admin::Command::StartAdmin].endpoint(admin::admin_entrypoint))
                .branch(case![admin::Command::Admin].endpoint(admin::admin_entrypoint))
            )
        )
        .branch(
            support::support_filter_async()
            .chain(
                Update::filter_message().filter_command::<support::Command>()
                .branch(case![support::Command::Support].endpoint(support::support_entrypoint))
            )
        )
        .branch(
            Update::filter_message().filter_command::<user::Command>()
            .branch(case![user::Command::Start(start)].endpoint(user::user_entrypoint))
            .branch(case![user::Command::Online].endpoint(user::online_command_handler)));

    //// Telegram Stars payment handlers
    //// Note: We handle successful_payment only due to teloxide-core bug with XTR currency
    let telegram_stars_handlers = Update::filter_message()
        .filter(|msg: Message| msg.successful_payment().is_some())
        .endpoint(handle_successful_payment);
    
    //// Raw update handler for pre_checkout_query (workaround for teloxide-core bug)
    let raw_update_handler = Update::filter_pre_checkout_query()
        .endpoint(handle_raw_update);

    dptree::entry()
        .branch(
            dptree::entry()
                .branch(telegram_stars_handlers)
                .branch(raw_update_handler)
        )
        .branch(
            dialogue::enter::<Update, ErasedStorage<MasterState>, MasterState, _>().chain(
            dialogue::enter::<Update, ErasedStorage<PurchaseState>, PurchaseState, _>().chain(
            dialogue::enter::<Update, ErasedStorage<GetProxyStates>, GetProxyStates, _>()
                .inspect(|| log::debug!("dialogue enter"))
                .map_async(map_profile)
                .inspect(|| log::debug!("map_profile"))
                .map_async(map_settings)
                .inspect(|| log::debug!("map_settings"))
                .branch(entrypoints)
                .branch(clear_state)
                .inspect(|| log::trace!("{}", "schema: admin".bright_black()))
                .branch(admin::schema())
                .inspect(|| log::trace!("{}", "schema: support".bright_black()))
                .branch(support::schema())
                .inspect(|| log::trace!("{}", "schema: user".bright_black()))
                .branch(user::schema())))
        )
}

async fn clear_state(
    bot: Bot,
    dialogue: MasterDialogue,
    dialogue_purchase: PurchaseDialogue,
    dialogue_get_proxy: GetProxyDialogue,
    message: Message,
    settings: HandlerSettings,
) -> Result<(), Box<dyn std::error::Error + Send + Sync + 'static>> {
    dialogue.clear().await?;
    dialogue_purchase.update(PurchaseState::default()).await?;
    dialogue_get_proxy.update(GetProxyStates::default()).await?;
    bot.send_message(message.chat.id, t8x!("State cleared", &settings.language)).await?;
    Ok(())
}
