use crate::ui::prelude::*;
use super::*;

pub fn schema() -> UpdateHandler<Box<dyn std::error::Error + Send + Sync + 'static>> {
    let menu_reply_handler = Update::filter_message()
        .chain(
        Message::filter_text()
            .branch(
                filter_localized_text!(Ru, "⏺️Прокси онлайн⏺️")
                    .endpoint(|bot, msg, settings: HandlerSettings| select_pool_handler_constructor(
                        bot,
                        msg, 
                        |pool| Callback::Online { pool }.to_string().to_string(), 
                        Some(Callback::BackFromOnline.to_string().to_string()),
                        SelectPoolHandlerSettings::from(settings)
                    ))
            )
            .branch(
                filter_localized_text!(Ru, "👤Профиль👤")
                    .endpoint(|bot: Bot, message: Message, dialogue: MasterDialogue, profile: Profile, settings: HandlerSettings| -> HandlerFn { Box::pin(async move {
                            profile_handler(
                                bot,
                                dialogue,
                                message,
                                profile,
                                settings.force_behavior(ForceHandlerBehavior::DeleteMessage)
                            ).await
                        })}
                    ),
            )
            .branch(
                filter_localized_text!(Ru, "ℹ️О насℹ️")
                .endpoint(about_us_handler),
            )
            .branch(
                filter_localized_text!(Ru, "💯Акции и предложения🚩")
                .endpoint(promotions_handler),
            )
            .branch(
                filter_localized_text!(Ru, "📖Условия и правила📖")
                .endpoint(terms_handler),
            )
            .branch(
                filter_localized_text!(Ru, "❓FAQ❓")
                .endpoint(faq_handler),
            )
            .branch(
                filter_localized_text!(Ru, "📝Блог📝")
                .endpoint(blog_handler),
            )
            .branch(
                filter_localized_text!(Ru, "🏠В главное меню🏠")
                .endpoint(start_message_handler),
            ),
    );

    let message_handler = Update::filter_message()
        .branch(
            case_expr![MasterState { user_kind: UserStateKind::ReceivePromo, .. }]
                .endpoint(receive_promo),
        )
        .branch(
            case_expr![MasterState { user_kind: UserStateKind::ReceiveEmail, .. }]
                .endpoint(receive_email),
        )
        .branch(
            case_expr![MasterState { user_kind: UserStateKind::ReceiveWithdrawAmount, .. }]
                .endpoint(receive_withdraw_amount),
        )
        .branch(
            case_expr![MasterState { user_kind: UserStateKind::ReceiveWithdrawComment { amount }, .. } => amount]
                .endpoint(receive_withdraw_comment),
        )
        .branch(
            case_expr![MasterState { user_kind: UserStateKind::ConfirmWithdraw { amount, comment }, .. } => (amount, comment)]
                .endpoint(confirm_withdraw),
        )
        .branch(
            case_expr![MasterState { user_kind: UserStateKind::ReceiveAccountPassword, .. }]
                .endpoint(receive_account_password),
        )
        .branch(
            case_expr![MasterState { user_kind: UserStateKind::ReceiveMergeAccountEmail, .. }]
                .endpoint(receive_merge_account_email),
        )
        .branch(
            case_expr![MasterState { user_kind: UserStateKind::ReceiveMergeAccountPassword { email_or_login }, .. } => email_or_login]
                .endpoint(receive_merge_account_password),
        )
        .branch(
            case_expr![MasterState { user_kind: UserStateKind::ReceiveIPToAdd { .. }, .. }]
                .endpoint(|bot: Bot, msg: Message, dialogue: MasterDialogue, settings: HandlerSettings| async move {
                if let Ok(Some(state)) = dialogue.get().await {
                    if let UserStateKind::ReceiveIPToAdd { selected_pool } = state.user_kind {
                        receive_ip_to_add(bot, msg, dialogue, selected_pool, settings).await
                    } else {
                        Ok(())
                    }
                } else {
                    Ok(())
                }
            }),
        )
        .branch(
            case_expr![MasterState { user_kind: UserStateKind::ReceiveIPToRemove { .. }, .. }]
                .endpoint(|bot: Bot, msg: Message, dialogue: MasterDialogue, settings: HandlerSettings| async move {
                if let Ok(Some(state)) = dialogue.get().await {
                    if let UserStateKind::ReceiveIPToRemove { selected_pool } = state.user_kind {
                        receive_ip_to_remove(bot, msg, dialogue, selected_pool, settings).await
                    } else {
                        Ok(())
                    }
                } else {
                    Ok(())
                }
            }),
        )
        .branch(
            case_expr![MasterState { user_kind: UserStateKind::ReceiveLanguage { .. }, .. }]
                .endpoint(|bot: Bot, msg: Message, settings: HandlerSettings| async move {
                    let ln = settings.language;
                    bot.send_message(msg.chat.id, t8x!(Ru, "Пожалуйста, выберите язык с помощью кнопок выше", &ln))
                        .await?;
                    Ok(())
                })
        )
        .branch(
            case_expr![MasterState { user_kind: UserStateKind::ReceiveRotationInterval { .. }, .. }]
                .endpoint(|bot: Bot, msg: Message, dialogue: MasterDialogue, settings: HandlerSettings| async move {
                    if let Ok(Some(state)) = dialogue.get().await {
                        if let UserStateKind::ReceiveRotationInterval { selected_pool } = state.user_kind {
                            receive_rotation_interval(bot, msg, dialogue, selected_pool, settings).await
                        } else {
                            Ok(())
                        }
                    } else {
                        Ok(())
                    }
                })
        )
        .endpoint(|bot: Bot, msg: Message, dialogue: MasterDialogue, settings: HandlerSettings| async move {
                let _ = bot.delete_message(msg.chat.id, msg.id).await;

                log::info!("Received message: {:?}", msg);
                
                start_message_handler(bot, dialogue, msg, settings).await
            }
        );

    let callback_query_handler = Update::filter_callback_query()
        .branch(
            Update::filter_callback_query()
            .filter(|q: CallbackQuery| {
                    if let Some(data) = q.data {
                        serde_json::from_str::<Callback>(&data).is_ok()
                    } else {
                        false
                    }
                }
            )
            .endpoint(callback_handler)
        );

    let get_proxy_schema = dptree::entry()
        .branch(
            Update::filter_callback_query()
            .filter(|q: CallbackQuery| {
                    if let Some(data) = q.data {
                        serde_json::from_str::<GetProxyCallback>(&data).is_ok()
                    } else {
                        false
                    }
                }
            )
            .chain(dptree::endpoint(get_proxy_callback_handler))
        )
        .branch(
            Update::filter_message()
            .chain(
                Message::filter_text()
                .branch(
                    dptree::entry().filter(|msg_text: String, settings: HandlerSettings| {
                            msg_text == t8x!(Ru, "⚙️Панель управления⚙️", &settings.language, "menu-button")
                    })
                    .endpoint(|bot: Bot, msg: Message, settings: HandlerSettings, profile: Profile| async move {
                        bot.delete_message(msg.chat.id, msg.id).await?;
                        let pools = profile.pools.keys().cloned().collect::<Vec<_>>();
                        select_pool_handler_constructor(
                            bot, 
                            msg, 
                            |pool| GetProxyCallback::GetProxy { pool }.to_string(), 
                            Some(Callback::DeleteThisMessage.to_string()),
                            SelectPoolHandlerSettings::from(settings)
                            .include_pools(pools)
                            .with_message(t8x!("<b>Only pools with purchased traffic available</b>", &settings.language)))
                        .await
                    })
                )
                .filter_async(|user_dialogue: MasterDialogue| async move {
                        let user_in_proxy_generation = if let Ok(Some(user_state)) = user_dialogue.get().await {
                            matches!(user_state.user_kind, UserStateKind::ProxyGeneration)
                        } else {
                            false
                        };

                        if !user_in_proxy_generation {
                            return false;
                        }

                        true
                })
                .branch(
                    dptree::entry().filter_async(|dialogue: GetProxyDialogue| async move {
                        let Ok(state_option) = dialogue.get().await else {
                            return false;
                        };
                        let Some(state) = state_option else {
                            return false;
                        };
                        matches!(state.step, ProxySelectionStep::ChoseSearchable { .. })
                    })
                    .endpoint(handle_search_query)
                )
                .branch(
                    dptree::entry()
                    .filter_async(|dialogue: GetProxyDialogue| async move {
                        let Ok(state_option) = dialogue.get().await else {
                            return false;
                        };
                        let Some(state) = state_option else {
                            return false;
                        };
                        matches!(state.step, ProxySelectionStep::ReceiveInterval)
                    })
                    .endpoint(handle_interval_input)
                )
                .branch(
                    dptree::entry()
                    .filter_async(|dialogue: GetProxyDialogue| async move {
                        let Ok(state_option) = dialogue.get().await else {
                            return false;
                        };
                        let Some(state) = state_option else {
                            return false;
                        };
                        matches!(state.step, ProxySelectionStep::ReceiveAmount)
                    })
                    .endpoint(handle_amount_input)
                )
            )
        );

    let purchase_schema = dptree::entry()
        .branch(
            Update::filter_callback_query()
            .filter(|q: CallbackQuery| {
                    if let Some(data) = q.data {
                        serde_json::from_str::<PurchaseCallback>(&data).is_ok()
                    } else {
                        false
                    }
                }
            )
            .chain(dptree::endpoint(purchase_callback_handler))
        )
        .branch(
            Update::filter_message()
            .chain(
                Message::filter_text()
                .filter_async(|user_dialogue: MasterDialogue| async move {
                        let user_in_purchase = if let Ok(Some(user_state)) = user_dialogue.get().await {
                            matches!(user_state.user_kind, UserStateKind::Purchase)
                        } else {
                            false
                        };

                        if !user_in_purchase {
                            return false;
                        }

                        true
                })
                .branch(
                    dptree::entry()
                    .filter_async(|dialogue: PurchaseDialogue| async move {
                        let Ok(state_option) = dialogue.get().await else {
                            return false;
                        };
                        let Some(state) = state_option else {
                            return false;
                        };
                        matches!(state.step, PurchaseStep::EnterAmount | PurchaseStep::SelectPaymentMethod)
                    })
                    .endpoint(purchase::handle_gb_amount_input)
                )
                .branch(
                    dptree::entry()
                    .filter_async(|dialogue: PurchaseDialogue| async move {
                        let Ok(state_option) = dialogue.get().await else {
                            return false;
                        };
                        let Some(state) = state_option else {
                            return false;
                        };
                        matches!(state.step, PurchaseStep::EnterPromocode)
                    })
                    .endpoint(purchase::handle_promocode_input)
                )
            )
        );

    let default_proxy_settings_callback_handler = Update::filter_callback_query()
            .filter_callback_data::<DefaultProxySettingsCallback>()
            .chain(dptree::endpoint(default_proxy_settings_callback_handler));


    dptree::entry()
        .branch(get_proxy_schema)
        .branch(menu_reply_handler)
        .branch(purchase_schema)
        .branch(callback_query_handler)
        .branch(default_proxy_settings_callback_handler)
        .branch(message_handler)
}
