смотри, в этом коде ошибка, когда я в главном меню и нажимаю "Получить sms", то у меня зачем-то дважды делается один и тот же запрос для получения списка сервисов, но в начале он делается с оператором None, а потом с опреатором из настроек пользовтаеля, я не вижу смысла в первом запросе, можно это как-то сократить и убарать, но чтобы это не сказалось на осталньом функционале, вот лог:
Nov 12 19:35:17 vps1707806210 python[30487]: 2024-11-12 19:35:17,737 - bot.handlers.start - INFO - Пользователь 389669884 запустил бота.
Nov 12 19:35:17 vps1707806210 python[30487]: 2024-11-12 19:35:17,908 - bot.handlers.start - INFO - Пользователь 389669884 вернулся в главное меню.
Nov 12 19:35:18 vps1707806210 python[30487]: 2024-11-12 19:35:18,251 - aiogram.event - INFO - Update id=600811445 is handled. Duration 514 ms by bot id=7633673561
Nov 12 19:35:23 vps1707806210 python[30487]: 2024-11-12 19:35:23,182 - bot.handlers.sms - INFO - Пользователь 389669884 начал процесс получения номера.
Nov 12 19:35:23 vps1707806210 python[30487]: 2024-11-12 19:35:23,182 - bot.api - INFO - Запрос статуса номеров для страны: 0, оператор: None
Nov 12 19:35:24 vps1707806210 python[30487]: 2024-11-12 19:35:24,406 - bot.api - INFO - Статус номеров: {'baa_0': '37744', 'bax_0': '36728', 'baw_0': '36781', 'aa_0': '25699', 'ac_0': '27579', 'ad_0': '37926', 'ae_0': '37783', 'ah_0': '24127', 'ai_0': '26000', 'ak_0': '39790', 'am_0': '35915', 'an_0': '38448', 'bbl_0': '37736', 'ao_0': '25379', 'bbo_0': '37002', 'bbs_0': '36591', 'at_0': '24048', 'av_0': '9511', 'bbt_0': '36765', 'aw_0': '36280', 'ax_0': '41026', 'bbv_0': '36769', 'ba_0': '23952', 'bd_0': '27958', 'bcf_0': '36863', 'bh_0': '24136', 'bcg_0': '36614', 'bi_0': '25677', 'bl_0': '38236', 'bm_0': '24137', 'bo_0': '38140', 'bco_0': '36845', 'br_0': '20300', 'bv_0': '38757', 'aat_0': '23576', 'bw_0': '26007', 'bz_0': '35380', 'cb_0': '25687', 'bdb_0': '36853', 'abd_0': '22832', 'bde_0': '36850', 'ce_0': '27210', 'bdi_0': '35573', 'abl_0': '23796', 'bdm_0': '35564', 'cm_0': '39788', 'abk_0': '25325', 'cn_0': '38283', 'abn_0': '24073', 'co_0': '38010', 'abm_0': '24087', 'cr_0': '23512', 'ct_0': '24146', 'cu_0': '24043', 'cy_0': '37165', 'abw_0': '23951', 'abz_0': '24072', 'aby_0': '23721', 'da_0': '20564', 'aca_0': '24077', 'dd_0': '25405', 'de_0': '36282', 'df_0': '38183', 'acd_0': '23835', 'acg_0': '23836', 'dh_0': '38565', 'dj_0': '24230', 'ach_0': '23800', 'do_0': '25687', 'bep_0': '35557', 'dp_0': '37931', 'beq_0': '35786', 'ds_0': '31500', 'dt_0': '23882', 'bes_0': '35565', 'acw_0': '23202', 'bez_0': '35563', 'dz_0': '38387', 'ee_0': '36192', 'en_0': '38248', 'adr_0': '23638', 'es_0': '35809', 'et_0': '38160', 'bfu_0': '35564', 'bft_0': '35543', 'adv_0': '23311', 'ew_0': '37468', 'adw_0': '23790', 'adz_0': '24032', 'ady_0': '24060', 'fb_0': '36804', 'bga_0': '35565', 'fd_0': '35073', 'aee_0': '24087', 'ff_0': '37892', 'aeg_0': '25829', 'bgj_0': '37421', 'aeh_0': '24062', 'aek_0': '24080', 'aej_0': '23420', 'ael_0': '25544', 'bgp_0': '35561', 'fs_0': '38111', 'aes_0': '24069', 'ft_0': '20791', 'fu_0': '37680', 'aeu_0': '25742', 'fx_0': '38722', 'bgw_0': '35564', 'fy_0': '36279', 'fz_0': '37662', 'gb_0': '38155', 'afa_0': '24236', 'gk_0': '23968', 'afl_0': '24087', 'gm_0': '38142', 'bhl_0': '36739', 'bho_0': '36724', 'go_0': '24843', 'bhn_0': '36740', 'gp_0': '37292', 'afp_0': '24052', 'afo_0': '23781', 'gr_0': '19499', 'gs_0': '25583', 'bhw_0': '24800', 'gw_0': '37648', 'afu_0': '24074', 'gx_0': '36215', 'bhx_0': '24431', 'gz_0': '38050', 'hb_0': '38025', 'hc_0': '38049', 'agd_0': '37954', 'hg_0': '38133', 'bii_0': '23833', 'bin_0': '23280', 'bim_0': '22979', 'ho_0': '26040', 'bip_0': '23058', 'agn_0': '25699', 'hu_0': '39756', 'agu_0': '23908', 'agt_0': '23946', 'hw_0': '37021', 'hx_0': '37990', 'hz_0': '35701', 'ahb_0': '25846', 'ahc_0': '23841', 'ig_0': '33116', 'ahe_0': '24111', 'ij_0': '38087', 'il_0': '36929', 'ahl_0': '25912', 'im_0': '39993', 'ahk_0': '24117', 'ahn_0': '24040', 'io_0': '38148', 'ip_0': '38135', 'iq_0': '37615', 'iw_0': '24137', 'ahx_0': '24139', 'ahz_0': '24068', 'ja_0': '25878', 'jc_0': '36821', 'aie_0': '24137', 'jf_0': '36253', 'aif_0': '24142', 'aim_0': '23910', 'ail_0': '23911', 'jo_0': '25649', 'jp_0': '24146', 'ain_0': '24146', 'jr_0': '35681', 'js_0': '23963', 'jv_0': '24131', 'jy_0': '24037', 'aiy_0': '24146', 'aiz_0': '24146', 'ajb_0': '24132', 'kd_0': '23950', 'ajd_0': '23931', 'ke_0': '35930', 'ajc_0': '24058', 'kf_0': '38193', 'kh_0': '23879', 'ajg_0': '23366', 'kj_0': '24081', 'kk_0': '25971', 'aji_0': '23449', 'ajl_0': '24139', 'kt_0': '38353', 'ajt_0': '24075', 'kz_0': '38150', 'lc_0': '28785', 'akb_0': '24175', 'ake_0': '24137', 'lf_0': '38087', 'akf_0': '24055', 'li_0': '38118', 'lm_0': '23892', 'ls_0': '38164', 'lt_0': '38088', 'lv_0': '38114', 'lx_0': '37936', 'lz_0': '25773', 'ma_0': '11796', 'mb_0': '37491', 'md_0': '20754', 'me_0': '38145', 'mg_0': '25568', 'mi_0': '23949', 'mj_0': '37931', 'mm_0': '36219', 'mo_0': '24715', 'mt_0': '36254', 'mv_0': '25640', 'mw_0': '24017', 'my_0': '38065', 'mz_0': '23941', 'nc_0': '25710', 'nf_0': '38130', 'ng_0': '23750', 'ami_0': '23880', 'nj_0': '24111', 'amk_0': '24117', 'nl_0': '25808', 'amn_0': '24060', 'nq_0': '36050', 'ns_0': '25330', 'nt_0': '22684', 'nv_0': '38079', 'nw_0': '23776', 'amy_0': '23613', 'amx_0': '23929', 'of_0': '24053', 'og_0': '36080', 'oi_0': '33002', 'oj_0': '26186', 'ok_0': '30102', 'ol_0': '38068', 'oo_0': '23638', 'anp_0': '23404', 'ot_0': '27647', 'ov_0': '23915', 'ow_0': '23901', 'aoi_0': '22634', 'pj_0': '23984', 'aoh_0': '21977', 'aok_0': '22801', 'aoj_0': '22804', 'pm_0': '37848', 'aom_0': '22794', 'pn_0': '24005', 'aol_0': '22801', 'po_0': '32917', 'aoo_0': '22811', 'pp_0': '37414', 'aon_0': '22751', 'ps_0': '23941', 'aos_0': '22583', 'aor_0': '22790', 'aou_0': '22811', 'pv_0': '23910', 'aot_0': '22801', 'pw_0': '23878', 'aov_0': '22305', 'qf_0': '35255', 'qh_0': '36317', 'qj_0': '37740', 'apj_0': '22141', 'qp_0': '24042', 'qq_0': '37906', 'qr_0': '34245', 'qs_0': '23830', 'apq_0': '35043', 'qv_0': '23956', 'qw_0': '10432', 'qx_0': '25752', 'apw_0': '22632', 'qz_0': '38214', 'apy_0': '22790', 'aqa_0': '22811', 'rc_0': '25376', 'rd_0': '35765', 're_0': '38263', 'aqd_0': '22823', 'rj_0': '38007', 'rl_0': '37372', 'rm_0': '38199', 'rn_0': '23197', 'ro_0': '23845', 'rq_0': '24020', 'aqq_0': '22672', 'aqr_0': '22752', 'aqt_0': '22811', 'sb_0': '36137', 'sd_0': '38211', 'sg_0': '11757', 'sh_0': '38167', 'sn_0': '37215', 'arr_0': '22756', 'st_0': '36228', 'sv_0': '37288', 'arv_0': '22811', 'sz_0': '24039', 'ta_0': '25438', 'tc_0': '28332', 'asb_0': '37808', 'tg_0': '3402', 'th_0': '38217', 'ti_0': '36151', 'asi_0': '22811', 'tk_0': '37583', 'ask_0': '22811', 'tl_0': '37928', 'tn_0': '37977', 'tp_0': '37937', 'ts_0': '37859', 'tv_0': '23619', 'tw_0': '38076', 'tx_0': '37462', 'ty_0': '24004', 'tz_0': '23860', 'ua_0': '24076', 'ub_0': '22819', 'ue_0': '39800', 'ate_0': '22811', 'ui_0': '35384', 'uk_0': '38008', 'um_0': '24007', 'uq_0': '23744', 'ato_0': '22811', 'us_0': '25718', 'atq_0': '22804', 'ut_0': '23744', 'uu_0': '20485', 'atu_0': '17816', 'ux_0': '23647', 'atx_0': '22811', 'vb_0': '23776', 'vd_0': '38016', 've_0': '36200', 'aug_0': '21425', 'vh_0': '23938', 'auf_0': '22654', 'vi_0': '18238', 'vj_0': '23835', 'vk_0': '371', 'vl_0': '23835', 'vm_0': '38089', 'vp_0': '38116', 'vq_0': '23948', 'aup_0': '36798', 'auu_0': '22788', 'aut_0': '22680', 'auv_0': '22840', 'vz_0': '25920', 'wa_0': '12856', 'wb_0': '28206', 'wc_0': '37955', 'wd_0': '34811', 'we_0': '39742', 'wp_0': '35572', 'avr_0': '22757', 'wt_0': '38040', 'wu_0': '23387', 'wx_0': '37357', 'wy_0': '23938', 'wz_0': '23835', 'xa_0': '23935', 'xc_0': '23531', 'awc_0': '22757', 'awb_0': '36774', 'xe_0': '35669', 'awe_0': '22736', 'awd_0': '22747', 'awf_0': '22758', 'xk_0': '38111', 'awk_0': '22751', 'xm_0': '24028', 'xn_0': '24122', 'xo_0': '23748', 'xp_0': '23537', 'xr_0': '37773', 'xt_0': '25800', 'aww_0': '22688', 'xx_0': '25670', 'awy_0': '22681', 'awx_0': '22688', 'ya_0': '8591', 'yd_0': '25744', 'ye_0': '23520', 'yf_0': '37434', 'yh_0': '23519', 'axg_0': '35054', 'yk_0': '36409', 'yl_0': '34481', 'ym_0': '26300', 'yo_0': '37953', 'yq_0': '23269', 'yu_0': '38139', 'yw_0': '37162', 'axu_0': '35069', 'yz_0': '36040', 'axy_0': '35140', 'za_0': '37309', 'ayg_0': '35345', 'zh_0': '38097', 'ayk_0': '34999', 'zl_0': '38000', 'zn_0': '39791', 'zo_0': '38030', 'zp_0': '23921', 'ayq_0': '35125', 'zr_0': '40020', 'zs_0': '38157', 'zx_0': '23951', 'azd_0': '35126', 'azs_0': '36662'}
Nov 12 19:35:24 vps1707806210 python[30487]: 2024-11-12 19:35:24,408 - bot.api - INFO - Запрос статуса номеров для страны: 0, оператор: any
Nov 12 19:35:25 vps1707806210 python[30487]: 2024-11-12 19:35:25,132 - bot.api - INFO - Статус номеров: {'baa_0': '37744', 'bax_0': '36728', 'baw_0': '36781', 'aa_0': '25699', 'ac_0': '27579', 'ad_0': '37926', 'ae_0': '37783', 'ah_0': '24127', 'ai_0': '26000', 'ak_0': '39790', 'am_0': '35915', 'an_0': '38448', 'bbl_0': '37736', 'ao_0': '25379', 'bbo_0': '37002', 'bbs_0': '36591', 'at_0': '24048', 'av_0': '9511', 'bbt_0': '36765', 'aw_0': '36280', 'ax_0': '41026', 'bbv_0': '36769', 'ba_0': '23952', 'bd_0': '27958', 'bcf_0': '36863', 'bh_0': '24136', 'bcg_0': '36614', 'bi_0': '25677', 'bl_0': '38236', 'bm_0': '24137', 'bo_0': '38140', 'bco_0': '36845', 'br_0': '20300', 'bv_0': '38757', 'aat_0': '23576', 'bw_0': '26007', 'bz_0': '35380', 'cb_0': '25687', 'bdb_0': '36853', 'abd_0': '22832', 'bde_0': '36850', 'ce_0': '27210', 'bdi_0': '35573', 'abl_0': '23796', 'bdm_0': '35564', 'cm_0': '39788', 'abk_0': '25325', 'cn_0': '38283', 'abn_0': '24073', 'co_0': '38010', 'abm_0': '24087', 'cr_0': '23512', 'ct_0': '24146', 'cu_0': '24043', 'cy_0': '37165', 'abw_0': '23951', 'abz_0': '24072', 'aby_0': '23721', 'da_0': '20564', 'aca_0': '24077', 'dd_0': '25405', 'de_0': '36282', 'df_0': '38183', 'acd_0': '23835', 'acg_0': '23836', 'dh_0': '38565', 'dj_0': '24230', 'ach_0': '23800', 'do_0': '25687', 'bep_0': '35557', 'dp_0': '37931', 'beq_0': '35786', 'ds_0': '31500', 'dt_0': '23882', 'bes_0': '35565', 'acw_0': '23202', 'bez_0': '35563', 'dz_0': '38387', 'ee_0': '36192', 'en_0': '38248', 'adr_0': '23638', 'es_0': '35809', 'et_0': '38160', 'bfu_0': '35564', 'bft_0': '35543', 'adv_0': '23311', 'ew_0': '37468', 'adw_0': '23790', 'adz_0': '24032', 'ady_0': '24060', 'fb_0': '36804', 'bga_0': '35565', 'fd_0': '35073', 'aee_0': '24087', 'ff_0': '37892', 'aeg_0': '25829', 'bgj_0': '37421', 'aeh_0': '24062', 'aek_0': '24080', 'aej_0': '23420', 'ael_0': '25544', 'bgp_0': '35561', 'fs_0': '38111', 'aes_0': '24069', 'ft_0': '20791', 'fu_0': '37680', 'aeu_0': '25742', 'fx_0': '38722', 'bgw_0': '35564', 'fy_0': '36279', 'fz_0': '37662', 'gb_0': '38155', 'afa_0': '24236', 'gk_0': '23968', 'afl_0': '24087', 'gm_0': '38142', 'bhl_0': '36739', 'bho_0': '36724', 'go_0': '24843', 'bhn_0': '36740', 'gp_0': '37292', 'afp_0': '24052', 'afo_0': '23781', 'gr_0': '19499', 'gs_0': '25583', 'bhw_0': '24800', 'gw_0': '37648', 'afu_0': '24074', 'gx_0': '36215', 'bhx_0': '24431', 'gz_0': '38050', 'hb_0': '38025', 'hc_0': '38049', 'agd_0': '37954', 'hg_0': '38133', 'bii_0': '23833', 'bin_0': '23280', 'bim_0': '22979', 'ho_0': '26040', 'bip_0': '23058', 'agn_0': '25699', 'hu_0': '39756', 'agu_0': '23908', 'agt_0': '23946', 'hw_0': '37021', 'hx_0': '37990', 'hz_0': '35701', 'ahb_0': '25846', 'ahc_0': '23841', 'ig_0': '33116', 'ahe_0': '24111', 'ij_0': '38087', 'il_0': '36929', 'ahl_0': '25912', 'im_0': '39993', 'ahk_0': '24117', 'ahn_0': '24040', 'io_0': '38148', 'ip_0': '38135', 'iq_0': '37615', 'iw_0': '24137', 'ahx_0': '24139', 'ahz_0': '24068', 'ja_0': '25878', 'jc_0': '36821', 'aie_0': '24137', 'jf_0': '36253', 'aif_0': '24142', 'aim_0': '23910', 'ail_0': '23911', 'jo_0': '25649', 'jp_0': '24146', 'ain_0': '24146', 'jr_0': '35681', 'js_0': '23963', 'jv_0': '24131', 'jy_0': '24037', 'aiy_0': '24146', 'aiz_0': '24146', 'ajb_0': '24132', 'kd_0': '23950', 'ajd_0': '23931', 'ke_0': '35930', 'ajc_0': '24058', 'kf_0': '38193', 'kh_0': '23879', 'ajg_0': '23366', 'kj_0': '24081', 'kk_0': '25971', 'aji_0': '23449', 'ajl_0': '24139', 'kt_0': '38353', 'ajt_0': '24075', 'kz_0': '38150', 'lc_0': '28785', 'akb_0': '24175', 'ake_0': '24137', 'lf_0': '38087', 'akf_0': '24055', 'li_0': '38118', 'lm_0': '23892', 'ls_0': '38164', 'lt_0': '38088', 'lv_0': '38114', 'lx_0': '37936', 'lz_0': '25773', 'ma_0': '11796', 'mb_0': '37491', 'md_0': '20754', 'me_0': '38145', 'mg_0': '25568', 'mi_0': '23949', 'mj_0': '37931', 'mm_0': '36219', 'mo_0': '24715', 'mt_0': '36254', 'mv_0': '25640', 'mw_0': '24017', 'my_0': '38065', 'mz_0': '23941', 'nc_0': '25710', 'nf_0': '38130', 'ng_0': '23750', 'ami_0': '23880', 'nj_0': '24111', 'amk_0': '24117', 'nl_0': '25808', 'amn_0': '24060', 'nq_0': '36050', 'ns_0': '25330', 'nt_0': '22684', 'nv_0': '38079', 'nw_0': '23776', 'amy_0': '23613', 'amx_0': '23929', 'of_0': '24053', 'og_0': '36080', 'oi_0': '33002', 'oj_0': '26186', 'ok_0': '30102', 'ol_0': '38068', 'oo_0': '23638', 'anp_0': '23404', 'ot_0': '27647', 'ov_0': '23915', 'ow_0': '23901', 'aoi_0': '22634', 'pj_0': '23984', 'aoh_0': '21977', 'aok_0': '22801', 'aoj_0': '22804', 'pm_0': '37848', 'aom_0': '22794', 'pn_0': '24005', 'aol_0': '22801', 'po_0': '32917', 'aoo_0': '22811', 'pp_0': '37414', 'aon_0': '22751', 'ps_0': '23941', 'aos_0': '22583', 'aor_0': '22790', 'aou_0': '22811', 'pv_0': '23910', 'aot_0': '22801', 'pw_0': '23878', 'aov_0': '22305', 'qf_0': '35255', 'qh_0': '36317', 'qj_0': '37740', 'apj_0': '22141', 'qp_0': '24042', 'qq_0': '37906', 'qr_0': '34245', 'qs_0': '23830', 'apq_0': '35043', 'qv_0': '23956', 'qw_0': '10432', 'qx_0': '25752', 'apw_0': '22632', 'qz_0': '38214', 'apy_0': '22790', 'aqa_0': '22811', 'rc_0': '25376', 'rd_0': '35765', 're_0': '38263', 'aqd_0': '22823', 'rj_0': '38007', 'rl_0': '37372', 'rm_0': '38199', 'rn_0': '23197', 'ro_0': '23845', 'rq_0': '24020', 'aqq_0': '22672', 'aqr_0': '22752', 'aqt_0': '22811', 'sb_0': '36137', 'sd_0': '38211', 'sg_0': '11757', 'sh_0': '38167', 'sn_0': '37215', 'arr_0': '22756', 'st_0': '36228', 'sv_0': '37288', 'arv_0': '22811', 'sz_0': '24039', 'ta_0': '25438', 'tc_0': '28332', 'asb_0': '37808', 'tg_0': '3402', 'th_0': '38217', 'ti_0': '36151', 'asi_0': '22811', 'tk_0': '37583', 'ask_0': '22811', 'tl_0': '37928', 'tn_0': '37977', 'tp_0': '37937', 'ts_0': '37859', 'tv_0': '23619', 'tw_0': '38076', 'tx_0': '37462', 'ty_0': '24004', 'tz_0': '23860', 'ua_0': '24076', 'ub_0': '22819', 'ue_0': '39800', 'ate_0': '22811', 'ui_0': '35384', 'uk_0': '38008', 'um_0': '24007', 'uq_0': '23744', 'ato_0': '22811', 'us_0': '25718', 'atq_0': '22804', 'ut_0': '23744', 'uu_0': '20485', 'atu_0': '17816', 'ux_0': '23647', 'atx_0': '22811', 'vb_0': '23776', 'vd_0': '38016', 've_0': '36200', 'aug_0': '21425', 'vh_0': '23938', 'auf_0': '22654', 'vi_0': '18238', 'vj_0': '23835', 'vk_0': '371', 'vl_0': '23835', 'vm_0': '38089', 'vp_0': '38116', 'vq_0': '23948', 'aup_0': '36798', 'auu_0': '22788', 'aut_0': '22680', 'auv_0': '22840', 'vz_0': '25920', 'wa_0': '12856', 'wb_0': '28206', 'wc_0': '37955', 'wd_0': '34811', 'we_0': '39742', 'wp_0': '35572', 'avr_0': '22757', 'wt_0': '38040', 'wu_0': '23387', 'wx_0': '37357', 'wy_0': '23938', 'wz_0': '23835', 'xa_0': '23935', 'xc_0': '23531', 'awc_0': '22757', 'awb_0': '36774', 'xe_0': '35669', 'awe_0': '22736', 'awd_0': '22747', 'awf_0': '22758', 'xk_0': '38111', 'awk_0': '22751', 'xm_0': '24028', 'xn_0': '24122', 'xo_0': '23748', 'xp_0': '23537', 'xr_0': '37773', 'xt_0': '25800', 'aww_0': '22688', 'xx_0': '25670', 'awy_0': '22681', 'awx_0': '22688', 'ya_0': '8591', 'yd_0': '25744', 'ye_0': '23520', 'yf_0': '37434', 'yh_0': '23519', 'axg_0': '35054', 'yk_0': '36409', 'yl_0': '34481', 'ym_0': '26300', 'yo_0': '37953', 'yq_0': '23269', 'yu_0': '38139', 'yw_0': '37162', 'axu_0': '35069', 'yz_0': '36040', 'axy_0': '35140', 'za_0': '37309', 'ayg_0': '35345', 'zh_0': '38097', 'ayk_0': '34999', 'zl_0': '38000', 'zn_0': '39791', 'zo_0': '38030', 'zp_0': '23921', 'ayq_0': '35125', 'zr_0': '40020', 'zs_0': '38157', 'zx_0': '23951', 'azd_0': '35126', 'azs_0': '36662'}




и вот код:

# bot/handlers/sms.py

import asyncio
import logging
import time
import json
from pathlib import Path
from typing import Optional, List, Tuple
from aiogram import Dispatcher, types, F
from aiogram.utils.keyboard import InlineKeyboardBuilder
from aiogram.fsm.context import FSMContext
from aiogram.fsm.state import State, StatesGroup

from ..data import get_user_api_key, get_user_operator, get_user_country
from ..api import SmsHubAPI
from ..utils import get_usd_to_rub_rate, safe_edit_or_send_message
from .start import send_main_menu
from .activation import user_activations, poll_for_sms
from ..constants.operators import OPERATOR_DISPLAY_NAMES
from ..constants.countries import COUNTRIES
from ..constants.services import SERVICE_DISPLAY_NAMES

logger = logging.getLogger(__name__)

class SmsOrderState(StatesGroup):
    waiting_for_service = State()
    waiting_for_max_price = State()

SERVICES: List[Tuple[str, str]] = list(SERVICE_DISPLAY_NAMES.items())
POPULARITY_FILE = Path("service_popularity.json")

def load_popularity_data() -> dict:
    if POPULARITY_FILE.exists():
        with open(POPULARITY_FILE, 'r', encoding='utf-8') as f:
            return json.load(f)
    return {}

def save_popularity_data(popularity_data: dict):
    with open(POPULARITY_FILE, 'w', encoding='utf-8') as f:
        json.dump(popularity_data, f, ensure_ascii=False, indent=4)

def update_service_popularity(service_code: str):
    popularity_data = load_popularity_data()
    if service_code in popularity_data:
        popularity_data[service_code] += 1
    else:
        popularity_data[service_code] = 1
    save_popularity_data(popularity_data)

def get_sorted_services(available_services: List[str]) -> List[Tuple[str, str]]:
    popularity_data = load_popularity_data()
    sorted_services = sorted(
        [(code, name) for code, name in SERVICES if code in available_services],
        key=lambda service: popularity_data.get(service[0], 0),
        reverse=True
    )
    return sorted_services

def get_service_pages(services: List[Tuple[str, str]], page_size: int = 18) -> List[List[Tuple[str, str]]]:
    pages = []
    for i in range(0, len(services), page_size):
        pages.append(services[i:i + page_size])
    return pages

def build_service_keyboard(page_number: int, available_services: List[str], services_with_numbers: set) -> InlineKeyboardBuilder:
    sorted_services = get_sorted_services(available_services)
    services_pages = get_service_pages(sorted_services)
    keyboard = InlineKeyboardBuilder()

    if page_number < len(services_pages):
        current_page = services_pages[page_number]

        for code, name in current_page:
            # Append a red circle emoji if the service does not have available numbers
            if code not in services_with_numbers:
                name += " 🔴"
            keyboard.button(text=name, callback_data=f"service_select:{code}")

        keyboard.adjust(3)
        
        if len(services_pages) > 1:  # Only show navigation buttons if more than one page exists
            nav_buttons = []
            if page_number > 0:
                nav_buttons.append(types.InlineKeyboardButton(text="⬅️ Назад", callback_data=f"service_page:{page_number - 1}"))
            # Centralize page number information
            nav_buttons.append(types.InlineKeyboardButton(text=f"Страница {page_number + 1}/{len(services_pages)}", callback_data="ignore"))
            if page_number < len(services_pages) - 1:
                nav_buttons.append(types.InlineKeyboardButton(text="➡️ Вперед", callback_data=f"service_page:{page_number + 1}"))
            keyboard.row(*nav_buttons)
        
        keyboard.row(types.InlineKeyboardButton(text="🔙 Назад в меню", callback_data="back_to_main_menu"))
    
    return keyboard

def get_service_message_text(total_services_with_numbers: int, total_services_for_country: int, services_with_operator: int, country_name: str, operator_name: str) -> str:
    return (
        f"🔢 *Общее кол-во сервисов:* `{total_services_for_country}`\n"
        f"💼 *Доступные сервисы (где есть номера):* `{total_services_with_numbers}`\n"
        f"✅ *Доступные сервисы (с вашими настройками оператора):* `{services_with_operator}`\n\n"
        f"— Нажмите на кнопку, чтобы выбрать сервис.\n"
        f"— Или введите название, чтобы найти сервис.\n\n"
        f"🐾 *Текущая страна:* `{country_name}`\n"
        f"📡 *Текущий оператор:* `{operator_name}`\n"
        f"_(Эти параметры можно изменить в настройках)_\n"
        f"\n_🔴 - нет номеров_"
    )

async def fetch_all_services(user_api_key: str, user_country_code: str, state: FSMContext) -> Tuple[Optional[List[str]], int, int]:
    smshub_api = SmsHubAPI(user_api_key)
    max_attempts = 3
    last_exception = None
    available_services = []
    services_with_numbers = set()

    for attempt in range(1, max_attempts + 1):
        try:
            numbers_status = await smshub_api.get_numbers_status(country=user_country_code)
            if numbers_status:
                # Все сервисы и сервисы с доступными номерами
                available_services = [service.split('_')[0] for service in numbers_status.keys()]
                services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}
                break
        except Exception as e:
            last_exception = e
            logger.error(f"Ошибка при запросе статуса всех сервисов, попытка {attempt}: {e}")

        data = await state.get_data()
        if data.get("cancel_request"):
            logger.info("Запрос на получение всех сервисов был отменен.")
            return None, 0, 0

        progress_text = f"Попытка {attempt}/{max_attempts} получения списка всех сервисов..."
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
        keyboard.adjust(1)

        await safe_edit_or_send_message(
            message=data.get('message'),
            new_text=progress_text,
            state=state,
            reply_markup=keyboard.as_markup()
        )

        await asyncio.sleep(5)

    if last_exception:
        logger.error(f"Ошибка при запросе всех сервисов: {last_exception}")
        return None, 0, 0

    return available_services, len(services_with_numbers), len(available_services)

async def get_sms_handler(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    user_api_key = get_user_api_key(callback_query.from_user.id)
    user_country_code = get_user_country(callback_query.from_user.id) or "0"
    user_operator = get_user_operator(callback_query.from_user.id) or "any"

    if not user_api_key:
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="⚙️ Настройки", callback_data="settings")
        keyboard.button(text="🔙 Назад", callback_data="back_to_main_menu")
        keyboard.adjust(1)
        await safe_edit_or_send_message(
            message=callback_query.message,
            new_text="Пожалуйста, сначала настройте ваш API ключ в разделе 'Настройки'.",
            state=state,
            reply_markup=keyboard.as_markup()
        )
        return

    logger.info(f"Пользователь {callback_query.from_user.id} начал процесс получения номера.")

    await state.update_data(message=callback_query.message, cancel_request=False)
    available_services, total_services_with_numbers, total_services_for_country = await fetch_all_services(user_api_key, user_country_code, state)

    country_name = COUNTRIES.get(user_country_code, 'Неизвестно')
    operator_name = OPERATOR_DISPLAY_NAMES.get(user_operator, 'Любой')

    await state.update_data(total_services_with_numbers=total_services_with_numbers, 
                            total_services_for_country=total_services_for_country,
                            country_name=country_name, 
                            operator_name=operator_name)

    if available_services is None:
        await send_main_menu(callback_query.message, state)
        return

    smshub_api = SmsHubAPI(user_api_key)
    numbers_status = await smshub_api.get_numbers_status(country=user_country_code, operator=user_operator)
    services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}

    services_with_operator = len(services_with_numbers)  # Количество сервисов с учетом настроек оператора

    keyboard = build_service_keyboard(page_number=0, available_services=available_services, services_with_numbers=services_with_numbers)
    message_text = get_service_message_text(total_services_with_numbers, total_services_for_country, services_with_operator, country_name, operator_name)

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text=message_text,
        state=state,
        reply_markup=keyboard.as_markup(),
        parse_mode="Markdown"
    )
    await state.set_state(SmsOrderState.waiting_for_service)
    await state.update_data(available_services=available_services)

async def go_back_to_service_selection(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")
    logger.info(f"Пользователь {callback_query.from_user.id} отменил операцию.")

    await state.update_data(cancel_request=True)

    data = await state.get_data()
    current_task = data.get('current_task')
    if current_task:
        current_task.cancel()

    # Обновите актуальные данные здесь
    available_services = data.get('available_services', [])
    total_services_with_numbers = data.get('total_services_with_numbers', len(available_services))
    total_services_for_country = data.get('total_services_for_country', len(available_services))
    country_name = data.get('country_name', 'Неизвестно')
    operator_name = data.get('operator_name', 'Любой')

    smshub_api = SmsHubAPI(get_user_api_key(callback_query.from_user.id))
    numbers_status = await smshub_api.get_numbers_status(country=get_user_country(callback_query.from_user.id), operator=get_user_operator(callback_query.from_user.id))
    services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}

    services_with_operator = len(services_with_numbers)  # Количество сервисов с учетом настроек оператора

    keyboard = build_service_keyboard(page_number=0, available_services=available_services, services_with_numbers=services_with_numbers)
    message_text = get_service_message_text(total_services_with_numbers, total_services_for_country, services_with_operator, country_name, operator_name)

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text=message_text,
        state=state,
        reply_markup=keyboard.as_markup(),
        parse_mode="Markdown"
    )

    await state.set_state(SmsOrderState.waiting_for_service)

async def back_to_main_menu(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")
    logger.info(f"Пользователь {callback_query.from_user.id} вернулся в главное меню.")

    await state.set_state(None)
    await send_main_menu(callback_query.message, state)

async def service_page_handler(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    page_number = int(callback_query.data.split(":")[1])
    data = await state.get_data()
    available_services = data.get('available_services', [])

    smshub_api = SmsHubAPI(get_user_api_key(callback_query.from_user.id))
    numbers_status = await smshub_api.get_numbers_status(country=get_user_country(callback_query.from_user.id), operator=get_user_operator(callback_query.from_user.id))
    services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}

    services_with_operator = len(services_with_numbers)  # Количество сервисов с учетом настроек оператора

    total_services_with_numbers = data.get('total_services_with_numbers', len(available_services))
    total_services_for_country = data.get('total_services_for_country', len(available_services))
    country_name = data.get('country_name', 'Неизвестно')
    operator_name = data.get('operator_name', 'Любой')

    keyboard = build_service_keyboard(page_number, available_services, services_with_numbers)
    message_text = get_service_message_text(total_services_with_numbers, total_services_for_country, services_with_operator, country_name, operator_name)

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text=message_text,
        state=state,
        reply_markup=keyboard.as_markup(),
        parse_mode="Markdown"
    )

async def service_selected_handler(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    service_code = callback_query.data.split(":")[1]
    update_service_popularity(service_code)

    await state.update_data(selected_service=service_code, cancel_request=False)
    task = asyncio.create_task(service_handler_logic(
        callback_query.message, state, user_id=callback_query.from_user.id, service_code=service_code, is_service_selection=True))
    await state.update_data(current_task=task)

async def service_handler(message: types.Message, state: FSMContext, user_id: Optional[int] = None):
    try:
        await message.delete()
    except Exception as e:
        logger.error(f"Не удалось удалить сообщение пользователя: {e}")

    user_input = message.text.strip().lower()

    if user_id is None:
        user_id = message.from_user.id

    logger.info(f"Пользователь {user_id} ввел сервис: {user_input}")

    data = await state.get_data()
    available_services = data.get('available_services', [])

    smshub_api = SmsHubAPI(get_user_api_key(user_id))
    numbers_status = await smshub_api.get_numbers_status(country=get_user_country(user_id), operator=get_user_operator(user_id))
    services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}

    matched_services = [
        (code, name) for code, name in SERVICE_DISPLAY_NAMES.items()
        if code in available_services and (user_input in name.lower() or user_input == code.lower())
    ]

    if matched_services:
        pages = get_service_pages(matched_services)
        page_number = 0
        keyboard = build_page_keyboard(pages, page_number, services_with_numbers)
        
        await state.update_data(matched_services=matched_services)

        await safe_edit_or_send_message(
            message=message,
            new_text="Пожалуйста, выберите один из представленных сервисов:\n_🔴 - нет номеров_",
            state=state,
            reply_markup=keyboard.as_markup(),
            parse_mode="Markdown"
        )
    else:
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="🔙 Назад к сервисам", callback_data="service_page:0")
        await safe_edit_or_send_message(
            message=message,
            new_text="Сервис не найден. Попробуйте ввести код или полное название сервиса.",
            state=state,
            reply_markup=keyboard.as_markup()
        )

def build_page_keyboard(service_pages, page_number: int, services_with_numbers: set) -> InlineKeyboardBuilder:
    keyboard = InlineKeyboardBuilder()
    if page_number < len(service_pages):
        current_page = service_pages[page_number]

        for code, name in current_page:
            # Append a red circle emoji if the service does not have available numbers
            if code not in services_with_numbers:
                name += " 🔴"
            keyboard.button(text=name, callback_data=f"service_select:{code}")

        keyboard.adjust(3)
        
        if len(service_pages) > 1:  # Only show navigation buttons if more than one page exists
            nav_buttons = []
            if page_number > 0:
                nav_buttons.append(types.InlineKeyboardButton(text="⬅️ Назад", callback_data=f"search_page:{page_number - 1}"))
            # Centralize page number information
            nav_buttons.append(types.InlineKeyboardButton(text=f"Страница {page_number + 1}/{len(service_pages)}", callback_data="ignore"))
            if page_number < len(service_pages) - 1:
                nav_buttons.append(types.InlineKeyboardButton(text="➡️ Вперед", callback_data=f"search_page:{page_number + 1}"))
            keyboard.row(*nav_buttons)
    
    keyboard.row(types.InlineKeyboardButton(text="🔙 Назад к сервисам", callback_data="service_page:0"))
    return keyboard

async def handle_search_page_navigation(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    page_number = int(callback_query.data.split(":")[1])
    data = await state.get_data()
    matched_services = data.get('matched_services', [])

    smshub_api = SmsHubAPI(get_user_api_key(callback_query.from_user.id))
    numbers_status = await smshub_api.get_numbers_status(country=get_user_country(callback_query.from_user.id), operator=get_user_operator(callback_query.from_user.id))
    services_with_numbers = {service.split('_')[0] for service, count in numbers_status.items() if int(count) > 0}

    pages = get_service_pages(matched_services)
    keyboard = build_page_keyboard(pages, page_number, services_with_numbers)

    await safe_edit_or_send_message(
        message=callback_query.message,
        new_text="Пожалуйста, выберите один из представленных сервисов:\n_🔴 - нет номеров_",
        state=state,
        reply_markup=keyboard.as_markup(),
        parse_mode="Markdown"
    )

async def service_handler_logic(message: types.Message, state: FSMContext, user_id: int, service_code: str, is_service_selection: bool = False):
    logger.info(f"Пользователь {user_id} выбрал сервис: {service_code}")

    user_api_key = get_user_api_key(user_id)
    user_operator = get_user_operator(user_id) or "any"
    user_country_code = get_user_country(user_id) or "0"
    country_name = COUNTRIES.get(user_country_code, user_country_code)

    if not user_api_key:
        await safe_edit_or_send_message(
            message=message,
            new_text="Пожалуйста, сначала настройте ваш API ключ в разделе 'Настройки'.",
            state=state
        )
        await state.set_state(None)
        await send_main_menu(message, state)
        return

    smshub_api = SmsHubAPI(user_api_key)
    usd_to_rub_rate = await get_usd_to_rub_rate()

    max_attempts = 3
    success = False
    last_exception = None

    try:
        for attempt in range(1, max_attempts + 1):
            data = await state.get_data()
            if data.get("cancel_request"):
                logger.info(f"Запрос для пользователя {user_id} был отменен.")
                return

            try:
                progress_text = f"Идет запрос {attempt}/{max_attempts}..."
                keyboard = InlineKeyboardBuilder()
                keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
                keyboard.adjust(1)

                await safe_edit_or_send_message(
                    message=message,
                    new_text=progress_text,
                    state=state,
                    reply_markup=keyboard.as_markup()
                )

                price_info = await smshub_api.get_price_for_service(service_code, country=user_country_code)
                numbers_status = await smshub_api.get_numbers_status(country=user_country_code, operator=user_operator)

                if data.get("cancel_request"):
                    logger.info(f"Запрос для пользователя {user_id} был отменен после получения данных.")
                    return

                if price_info and numbers_status:
                    service_key = f"{service_code}_0"
                    available_numbers = int(numbers_status.get(service_key, 0) or 0)
                    
                    if available_numbers > 0:
                        prices = [float(price_str) for price_str in price_info.keys() if price_str is not None]
                        if prices:
                            min_price_usd = min(prices)
                            max_price_usd = max(prices)
                            min_price_rub = min_price_usd * usd_to_rub_rate if usd_to_rub_rate else 0
                            max_price_rub = max_price_usd * usd_to_rub_rate if usd_to_rub_rate else 0

                            operator_display = OPERATOR_DISPLAY_NAMES.get(user_operator, user_operator)
                            service_display = SERVICE_DISPLAY_NAMES.get(service_code, service_code)

                            keyboard = InlineKeyboardBuilder()
                            keyboard.button(text=f"⬇️ Мин. цена ({min_price_usd:.4f}$)", callback_data=f"select_price:{min_price_usd}")
                            keyboard.button(text=f"⬆️ Макс. цена ({max_price_usd:.4f}$)", callback_data=f"select_price:{max_price_usd}")
                            keyboard.adjust(2)
                            keyboard.row(types.InlineKeyboardButton(text="❌ Отмена", callback_data="cancel_operation"))

                            message_text = (
                                f"*Страна:* `{country_name}`\n"
                                f"*Доступно номеров:* `{available_numbers}`\n"
                                f"*Оператор:* `{operator_display}`\n"
                                f"*Сервис:* `{service_display}`\n"
                                f"*Цены:* от `{min_price_usd:.4f}` $ (₽{min_price_rub:.2f}) до `{max_price_usd:.4f}` $ (₽{max_price_rub:.2f}).\n\n"
                                f"_Выберите максимальную допустимую стоимость покупки с помощью кнопок ниже или введите сумму вручную (например: 0.5). Все суммы указаны в долларах ($):_"
                            )

                            await safe_edit_or_send_message(
                                message=message,
                                new_text=message_text,
                                state=state,
                                reply_markup=keyboard.as_markup(),
                                parse_mode="Markdown"
                            )

                            await state.update_data(
                                service=service_code,
                                service_display=service_display,
                                country_name=country_name,
                                available_numbers=available_numbers,
                                operator_display=operator_display,
                                min_price=min_price_usd,
                                max_price_usd=max_price_usd,
                                min_price_rub=min_price_rub,
                                max_price_rub=max_price_rub,
                                usd_to_rub_rate=usd_to_rub_rate,
                                user_id=user_id
                            )

                            await state.set_state(SmsOrderState.waiting_for_max_price)
                            success = True
                            break
                        else:
                            logger.info(f"Попытка {attempt}: Цены не найдены.")
                            last_exception = "Цены не найдены"
                    else:
                        logger.info(f"Попытка {attempt}: Нет доступных номеров.")
                        last_exception = "Нет доступных номеров"

            except Exception as e:
                logger.error(f"Ошибка при получении данных для сервиса '{service_code}', попытка {attempt}: {e}")
                last_exception = e

            await asyncio.sleep(5)

    except asyncio.CancelledError:
        logger.info(f"Задача для пользователя {user_id} была отменена.")
        return

    if not success:
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="Назад", callback_data="service_page:0")
        await safe_edit_or_send_message(
            message=message,
            new_text=f"Произошла ошибка при обработке запроса: {last_exception}. Попробуйте снова.",
            state=state,
            reply_markup=keyboard.as_markup()
        )

async def price_selected_handler(callback_query: types.CallbackQuery, state: FSMContext):
    try:
        await callback_query.answer()
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

    price = float(callback_query.data.split(":")[1])
    await state.update_data(max_price=price)

    await process_number_purchase(callback_query.message, state)

async def max_price_handler(message: types.Message, state: FSMContext):
    max_price_input = message.text.strip()
    data = await state.get_data()
    user_id = data.get('user_id', message.from_user.id)

    try:
        await message.delete()
    except Exception as e:
        logger.error(f"Не удалось удалить сообщение пользователя: {e}")

    logger.info(f"Пользователь {user_id} указал максимальную стоимость: {max_price_input}")

    try:
        max_price = float(max_price_input)
    except ValueError:
        user_data = await state.get_data()
        min_price = user_data.get('min_price', 0)
        max_price_usd = user_data.get('max_price_usd', 0)
        min_price_rub = user_data.get('min_price_rub', 0)
        max_price_rub = user_data.get('max_price_rub', 0)

        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
        keyboard.adjust(1)
        await safe_edit_or_send_message(
            message=message,
            new_text=(
                f"Пожалуйста, введите корректное число для максимальной стоимости. "
                f"От `{min_price:.4f}` $ (₽{min_price_rub:.2f}) до `{max_price_usd:.4f}` $ (₽{max_price_rub:.2f})."
            ),
            state=state,
            reply_markup=keyboard.as_markup(),
            parse_mode="Markdown"
        )
        return

    if max_price < data.get('min_price', 0):
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
        keyboard.adjust(1)
        await safe_edit_or_send_message(
            message=message,
            new_text=f"Максимальная стоимость должна быть не менее `{data.get('min_price', 0):.4f}` $.",
            state=state,
            reply_markup=keyboard.as_markup(),
            parse_mode="Markdown"
        )
        return

    await state.update_data(max_price=max_price)

    await process_number_purchase(message, state)

async def process_number_purchase(message: types.Message, state: FSMContext):
    user_data = await state.get_data()
    user_id = user_data.get('user_id', message.from_user.id)
    service = user_data['service']
    service_display = user_data['service_display']
    country_name = user_data['country_name']
    operator_display = user_data['operator_display']
    max_price = user_data['max_price']
    user_api_key = get_user_api_key(user_id)
    smshub_api = SmsHubAPI(user_api_key)
    user_country_code = get_user_country(user_id) or "0"

    max_attempts = 3
    last_exception = None

    try:
        for attempt in range(1, max_attempts + 1):
            data = await state.get_data()

            if data.get("cancel_request"):
                logger.info(f"Запрос на получение номера для пользователя {user_id} был отменен.")
                return
            
            progress_text = f"Идет запрос {attempt}/{max_attempts} на получение номера..."
            keyboard = InlineKeyboardBuilder()
            keyboard.button(text="❌ Отмена", callback_data="cancel_operation")
            keyboard.adjust(1)

            await safe_edit_or_send_message(
                message=message,
                new_text=progress_text,
                state=state,
                reply_markup=keyboard.as_markup()
            )

            user_operator = get_user_operator(user_id) or "any"

            if data.get("cancel_request"):
                logger.info(f"Запрос на получение номера для пользователя {user_id} был отменен перед выполнением.")
                return

            result = await smshub_api.get_number(service, country=user_country_code, max_price=max_price, operator=user_operator)

            if data.get("cancel_request"):
                logger.info(f"Запрос на получение номера для пользователя {user_id} был отменен.")
                return

            if result and result.startswith("ACCESS_NUMBER"):
                _, activation_id, number = result.split(":")
                logger.info(f"Пользователь {user_id} получил номер: {number}, активация ID: {activation_id}")

                if user_id not in user_activations:
                    user_activations[user_id] = {}
                user_activations[user_id][activation_id] = {
                    'number': number,
                    'status': 'Ожидание SMS',
                    'service': service,
                    'service_display': service_display,
                    'country_name': country_name,
                    'last_update': time.time(),
                    'task': None
                }

                keyboard = InlineKeyboardBuilder()
                keyboard.button(text="📂 Текущие активации", callback_data="current_activations")
                keyboard.button(text="❌ Отменить активацию", callback_data=f"cancel_activation:{activation_id}")
                keyboard.button(text="🔙 Главное меню", callback_data="back_to_main_menu")
                keyboard.adjust(1)

                message_text = (
                    f"*Получен номер:* `{number}`\n"
                    f"*Страна:* `{country_name}`\n"
                    f"*Оператор:* `{operator_display}`\n"
                    f"*Сервис:* `{service_display}`\n"
                    f"*Максимальная стоимость:* `{max_price:.2f}` $ (₽{max_price * user_data['usd_to_rub_rate']:.2f})\n"
                    f"*Статус:* *Ожидание SMS*\n"
                    f"Вы можете управлять активацией или вернуться в главное меню."
                )

                sent_message = await safe_edit_or_send_message(
                    message=message,
                    new_text=message_text,
                    state=state,
                    reply_markup=keyboard.as_markup(),
                    parse_mode="Markdown"
                )
                user_activations[user_id][activation_id]['message_id'] = sent_message.message_id

                await state.set_state(None)

                task = asyncio.create_task(poll_for_sms(
                    bot=message.bot,
                    user_id=user_id,
                    chat_id=message.chat.id,
                    activation_id=activation_id,
                    smshub_api=smshub_api
                ))
                user_activations[user_id][activation_id]['task'] = task
                return

            elif result == "NO_NUMBERS":
                logger.info(f"Попытка {attempt} из {max_attempts}: нет доступных номеров.")
                last_exception = result
                if attempt == max_attempts:
                    suggestion = (
                        "Попробуйте выбрать 'Любой оператор' в настройках или увеличить максимальную цену."
                        if user_operator != "any" else
                        "Попробуйте увеличить максимальную цену или повторите попытку позже."
                    )
                    keyboard = InlineKeyboardBuilder()
                    keyboard.button(text="Назад", callback_data="service_page:0")
                    await safe_edit_or_send_message(
                        message=message,
                        new_text=f"Нет доступных номеров для оператора {operator_display} по данной цене.\n{suggestion}",
                        state=state,
                        reply_markup=keyboard.as_markup()
                    )
                    return
            else:
                raise Exception("Неожиданный ответ API")

            await asyncio.sleep(5)

    except asyncio.CancelledError:
        logger.info(f"Задача для пользователя {user_id} была отменена.")
        return

    if last_exception and last_exception != "NO_NUMBERS":
        keyboard = InlineKeyboardBuilder()
        keyboard.button(text="Назад", callback_data="service_page:0")
        await safe_edit_or_send_message(
            message=message,
            new_text=f"Произошла ошибка при обработке запроса: {last_exception}. Попробуйте снова.",
            state=state,
            reply_markup=keyboard.as_markup()
        )

# Add a handler for the "ignore" callback to silently ignore it
async def ignore_callback_handler(callback_query: types.CallbackQuery):
    try:
        await callback_query.answer()  # Just answer to confirm the action
    except Exception as e:
        logger.warning(f"Не удалось ответить на callback_query: {e}")

def register_sms_handlers(dp: Dispatcher):
    dp.callback_query.register(get_sms_handler, F.data == "get_sms")
    dp.callback_query.register(go_back_to_service_selection, F.data == "cancel_operation")
    dp.callback_query.register(back_to_main_menu, F.data == "back_to_main_menu")
    dp.callback_query.register(service_page_handler, F.data.startswith("service_page:"))
    dp.callback_query.register(service_selected_handler, F.data.startswith("service_select:"))
    dp.callback_query.register(handle_search_page_navigation, F.data.startswith("search_page:"))
    dp.callback_query.register(price_selected_handler, F.data.startswith("select_price:"))
    dp.callback_query.register(ignore_callback_handler, F.data == "ignore")
    dp.message.register(service_handler, SmsOrderState.waiting_for_service)
    dp.message.register(max_price_handler, SmsOrderState.waiting_for_max_price)