//
// Copyright Aliaksei Levin (levlam@telegram.org), Arseny Smirnov (arseny30@gmail.com) 2014-2026
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
//
#include "td/telegram/LinkManager.h"

#include "td/telegram/MessageEntity.h"
#include "td/telegram/td_api.h"

#include "td/utils/common.h"
#include "td/utils/logging.h"
#include "td/utils/misc.h"
#include "td/utils/tests.h"

static void check_find_urls(const td::string &url, bool is_valid) {
  auto url_lower = td::to_lower(url);
  {
    auto tg_urls = td::find_tg_urls(url);
    if (is_valid && (td::begins_with(url_lower, "tg://") || td::begins_with(url_lower, "ton://"))) {
      ASSERT_EQ(1u, tg_urls.size());
      ASSERT_STREQ(url, tg_urls[0]);
    } else {
      ASSERT_TRUE(tg_urls.empty() || tg_urls[0] != url);
    }
  }

  {
    if (is_valid && (td::begins_with(url_lower, "http") || td::begins_with(url_lower, "t.me")) &&
        url.find('.') != td::string::npos && url.find(' ') == td::string::npos && url != "http://.." &&
        url.find("ra.ph") == td::string::npos && url.find("Aph") == td::string::npos) {
      auto urls = td::find_urls(url);
      ASSERT_EQ(1u, urls.size());
      ASSERT_STREQ(url, urls[0].first);
    }
  }
}

static void check_link(const td::string &url, const td::string &expected) {
  auto result = td::LinkManager::check_link(url);
  if (result.is_ok()) {
    ASSERT_STREQ(expected, result.ok());
  } else {
    ASSERT_TRUE(expected.empty());
  }

  check_find_urls(url, result.is_ok());
}

TEST(Link, check_link) {
  check_link("sftp://google.com", "");
  check_link("tg://google_com", "tg://google_com/");
  check_link("tOn://google", "ton://google/");
  check_link("httP://google.com?1#tes", "http://google.com/?1#tes");
  check_link("httPs://google.com/?1#tes", "https://google.com/?1#tes");
  check_link("http://google.com:0", "");
  check_link("http://google.com:0000000001", "http://google.com:1/");
  check_link("http://google.com:-1", "");
  check_link("tg://google?1#tes", "tg://google?1#tes");
  check_link("tg://google/?1#tes", "tg://google?1#tes");
  check_link("TG:_", "tg://_/");
  check_link("sftp://google.com", "");
  check_link("sftp://google.com", "");
  check_link("http:google.com", "");
  check_link("tg://http://google.com", "");
  check_link("tg:http://google.com", "");
  check_link("tg:https://google.com", "");
  check_link("tg:test@google.com", "");
  check_link("tg:google.com:80", "");
  check_link("tg:google-com", "tg://google-com/");
  check_link("tg:google.com", "");
  check_link("tg:google.com:0", "");
  check_link("tg:google.com:a", "");
  check_link("tg:[2001:db8:0:0:0:ff00:42:8329]", "");
  check_link("tg:127.0.0.1", "");
  check_link("http://[2001:db8:0:0:0:ff00:42:8329]", "http://[2001:db8:0:0:0:ff00:42:8329]/");
  check_link("http://localhost", "");
  check_link("http://..", "http://../");
  check_link("..", "http://../");
  check_link("https://.", "");
  check_link("tOnSiTe://google", "tonsite://google/");
  check_link("tOnSiTe://google.ton?t=1#we", "tonsite://google.ton?t=1#we");
}

static td::td_api::object_ptr<td::td_api::InternalLinkType> get_internal_link_type_object(
    const td::unique_ptr<td::LinkManager::InternalLink> &link) {
  auto object = link->get_internal_link_type_object();
  if (object->get_id() == td::td_api::internalLinkTypeMessageDraft::ID) {
    static_cast<td::td_api::internalLinkTypeMessageDraft *>(object.get())->text_->entities_.clear();
  }
  return object;
}

static void parse_internal_link(const td::string &url, td::td_api::object_ptr<td::td_api::InternalLinkType> expected) {
  auto result = td::LinkManager::parse_internal_link(url);
  if (result != nullptr) {
    auto object = get_internal_link_type_object(result);
    ASSERT_STREQ(url + ' ' + to_string(expected), url + ' ' + to_string(object));

    for (auto is_internal : {true, false}) {
      if (!is_internal && expected->get_id() == td::td_api::internalLinkTypeChatBoost::ID) {
        // external chat boost links must be generated with getChatBoostLink
        continue;
      }
      if (!is_internal && expected->get_id() == td::td_api::internalLinkTypeMessage::ID) {
        // external message links must be generated with getMessageLink
        continue;
      }
      if (expected->get_id() == td::td_api::internalLinkTypeQrCodeAuthentication::ID) {
        // QR code authentication links must never be generated manually
        continue;
      }
      auto r_link = td::LinkManager::get_internal_link(expected, is_internal);
      if (r_link.is_error()) {
        if (r_link.error().message() == "HTTP link is unavailable for the link type") {
          // some links are tg-only
          continue;
        }
        if (r_link.error().message() == "Deep link is unavailable for the link type") {
          // some links are HTTP-only
          continue;
        }
        if (r_link.error().message() == "WALLPAPER_INVALID") {
          continue;
        }
        LOG(ERROR) << url << ' ' << r_link.error() << ' ' << to_string(expected);
        ASSERT_TRUE(r_link.is_ok());
      }
      auto new_result = td::LinkManager::parse_internal_link(r_link.ok());
      ASSERT_TRUE(new_result != nullptr);
      auto new_object = get_internal_link_type_object(new_result);

      auto new_object_str = to_string(new_object);
      auto expected_str = to_string(expected);
      if (expected->get_id() == td::td_api::internalLinkTypeBackground::ID) {
        for (auto &c : expected_str) {
          if (c == '~') {
            // getInternalLink always use '-'
            c = '-';
          }
        }
        if (new_object_str != expected_str && td::ends_with(expected_str, "\"\n}\n")) {
          // getInternalLink always adds rotation parameter, because default value differs between apps
          expected_str = expected_str.substr(0, expected_str.size() - 4) + "?rotation=0\"\n}\n";
        }
      }
      ASSERT_EQ(new_object_str, expected_str);

      r_link = td::LinkManager::get_internal_link(new_object, is_internal);
      ASSERT_TRUE(r_link.is_ok());
      new_result = td::LinkManager::parse_internal_link(r_link.ok());
      ASSERT_TRUE(new_result != nullptr);

      // the object must be the same after 2 round of conversion
      ASSERT_STREQ(to_string(new_object), to_string(get_internal_link_type_object(new_result)));
    }
  } else {
    LOG_IF(ERROR, expected != nullptr) << url;
    ASSERT_TRUE(expected == nullptr);
  }

  check_find_urls(url, result != nullptr);
}

static auto chat_administrator_rights(bool can_manage_chat, bool can_change_info, bool can_post_messages,
                                      bool can_edit_messages, bool can_delete_messages, bool can_invite_users,
                                      bool can_restrict_members, bool can_pin_messages, bool can_manage_topics,
                                      bool can_promote_members, bool can_manage_video_chats, bool can_post_stories,
                                      bool can_edit_stories, bool can_delete_stories, bool can_manage_direct_messages,
                                      bool can_manage_tags, bool is_anonymous) {
  return td::td_api::make_object<td::td_api::chatAdministratorRights>(
      can_manage_chat, can_change_info, can_post_messages, can_edit_messages, can_delete_messages, can_invite_users,
      can_restrict_members, can_pin_messages, can_manage_topics, can_promote_members, can_manage_video_chats,
      can_post_stories, can_edit_stories, can_delete_stories, can_manage_direct_messages, can_manage_tags,
      is_anonymous);
}

static auto settings(td::td_api::object_ptr<td::td_api::SettingsSection> section = nullptr) {
  return td::td_api::make_object<td::td_api::internalLinkTypeSettings>(std::move(section));
}

static auto appearance(td::string subsection = td::string()) {
  return settings(td::td_api::make_object<td::td_api::settingsSectionAppearance>(subsection));
}

static auto ask_question() {
  return settings(td::td_api::make_object<td::td_api::settingsSectionAskQuestion>());
}

static auto business(td::string subsection = td::string()) {
  return settings(td::td_api::make_object<td::td_api::settingsSectionBusiness>(subsection));
}

static auto chat_folder_settings(td::string subsection = td::string()) {
  return settings(td::td_api::make_object<td::td_api::settingsSectionChatFolders>(subsection));
}

static auto data_and_storage_settings(td::string subsection = td::string()) {
  return settings(td::td_api::make_object<td::td_api::settingsSectionDataAndStorage>(subsection));
}

static auto devices(td::string subsection = td::string()) {
  return settings(td::td_api::make_object<td::td_api::settingsSectionDevices>(subsection));
}

static auto edit_profile_settings(td::string subsection = td::string()) {
  return settings(td::td_api::make_object<td::td_api::settingsSectionEditProfile>(subsection));
}

static auto faq() {
  return settings(td::td_api::make_object<td::td_api::settingsSectionFaq>());
}

static auto features() {
  return settings(td::td_api::make_object<td::td_api::settingsSectionFeatures>());
}

static auto in_app_browser(td::string subsection = td::string()) {
  return settings(td::td_api::make_object<td::td_api::settingsSectionInAppBrowser>(subsection));
}

static auto language_settings(td::string subsection = td::string()) {
  return settings(td::td_api::make_object<td::td_api::settingsSectionLanguage>(subsection));
}

static auto my_stars(td::string subsection = td::string()) {
  return settings(td::td_api::make_object<td::td_api::settingsSectionMyStars>(subsection));
}

static auto my_toncoins() {
  return settings(td::td_api::make_object<td::td_api::settingsSectionMyToncoins>());
}

static auto notification_settings(td::string subsection = td::string()) {
  return settings(td::td_api::make_object<td::td_api::settingsSectionNotifications>(subsection));
}

static auto power_saving(td::string subsection = td::string()) {
  return settings(td::td_api::make_object<td::td_api::settingsSectionPowerSaving>(subsection));
}

static auto premium() {
  return settings(td::td_api::make_object<td::td_api::settingsSectionPremium>());
}

static auto privacy_and_security_settings(td::string subsection = td::string()) {
  return settings(td::td_api::make_object<td::td_api::settingsSectionPrivacyAndSecurity>(subsection));
}

static auto privacy_policy() {
  return settings(td::td_api::make_object<td::td_api::settingsSectionPrivacyPolicy>());
}

static auto qr_code(td::string subsection = td::string()) {
  return settings(td::td_api::make_object<td::td_api::settingsSectionQrCode>(subsection));
}

static auto send_gift(td::string subsection = td::string()) {
  return settings(td::td_api::make_object<td::td_api::settingsSectionSendGift>(subsection));
}

static auto settings_search() {
  return settings(td::td_api::make_object<td::td_api::settingsSectionSearch>());
}

static auto target_chat_chosen(bool allow_users, bool allow_bots, bool allow_groups, bool allow_channels) {
  return td::td_api::make_object<td::td_api::targetChatChosen>(
      td::td_api::make_object<td::td_api::targetChatTypes>(allow_users, allow_bots, allow_groups, allow_channels));
}

static td::td_api::object_ptr<td::td_api::WebAppOpenMode> web_app_open_mode(bool is_compact, bool is_full_screen) {
  if (is_compact) {
    return td::td_api::make_object<td::td_api::webAppOpenModeCompact>();
  }
  if (is_full_screen) {
    return td::td_api::make_object<td::td_api::webAppOpenModeFullScreen>();
  }
  return td::td_api::make_object<td::td_api::webAppOpenModeFullSize>();
}

static auto attachment_menu_bot(td::td_api::object_ptr<td::td_api::targetChatChosen> chat_types,
                                td::td_api::object_ptr<td::td_api::InternalLinkType> chat_link,
                                const td::string &bot_username, const td::string &start_parameter) {
  td::td_api::object_ptr<td::td_api::TargetChat> target_chat;
  if (chat_link != nullptr) {
    target_chat = td::td_api::make_object<td::td_api::targetChatInternalLink>(std::move(chat_link));
  } else if (chat_types != nullptr) {
    target_chat = std::move(chat_types);
  } else {
    target_chat = td::td_api::make_object<td::td_api::targetChatCurrent>();
  }
  return td::td_api::make_object<td::td_api::internalLinkTypeAttachmentMenuBot>(
      std::move(target_chat), bot_username, start_parameter.empty() ? td::string() : "start://" + start_parameter);
}

static auto authentication_code(const td::string &code) {
  return td::td_api::make_object<td::td_api::internalLinkTypeAuthenticationCode>(code);
}

static auto background(const td::string &background_name) {
  return td::td_api::make_object<td::td_api::internalLinkTypeBackground>(background_name);
}

static auto bot_add_to_channel(const td::string &bot_username,
                               td::td_api::object_ptr<td::td_api::chatAdministratorRights> &&administrator_rights) {
  return td::td_api::make_object<td::td_api::internalLinkTypeBotAddToChannel>(bot_username,
                                                                              std::move(administrator_rights));
}

static auto bot_start(const td::string &bot_username, const td::string &start_parameter) {
  return td::td_api::make_object<td::td_api::internalLinkTypeBotStart>(bot_username, start_parameter, false);
}

static auto bot_start_in_group(const td::string &bot_username, const td::string &start_parameter,
                               td::td_api::object_ptr<td::td_api::chatAdministratorRights> &&administrator_rights) {
  return td::td_api::make_object<td::td_api::internalLinkTypeBotStartInGroup>(bot_username, start_parameter,
                                                                              std::move(administrator_rights));
}

static auto business_chat(const td::string &link_name) {
  return td::td_api::make_object<td::td_api::internalLinkTypeBusinessChat>(link_name);
}

static auto calls_page(const td::string &section) {
  return td::td_api::make_object<td::td_api::internalLinkTypeCallsPage>(section);
}

static auto chat_affiliate_program(const td::string &username, const td::string &referral) {
  return td::td_api::make_object<td::td_api::internalLinkTypeChatAffiliateProgram>(username, referral);
}

static auto chat_boost(const td::string &url) {
  return td::td_api::make_object<td::td_api::internalLinkTypeChatBoost>(url);
}

static auto chat_folder_invite(const td::string &slug) {
  return td::td_api::make_object<td::td_api::internalLinkTypeChatFolderInvite>("tg:addlist?slug=" + slug);
}

static auto chat_invite(const td::string &hash) {
  return td::td_api::make_object<td::td_api::internalLinkTypeChatInvite>("tg:join?invite=" + hash);
}

static auto chat_selection() {
  return td::td_api::make_object<td::td_api::internalLinkTypeChatSelection>();
}

static auto contacts_page(const td::string &section) {
  return td::td_api::make_object<td::td_api::internalLinkTypeContactsPage>(section);
}

static auto direct_messages_chat(const td::string &channel_username) {
  return td::td_api::make_object<td::td_api::internalLinkTypeDirectMessagesChat>(channel_username);
}

static auto game(const td::string &bot_username, const td::string &game_short_name) {
  return td::td_api::make_object<td::td_api::internalLinkTypeGame>(bot_username, game_short_name);
}

static auto gift_auction(const td::string &slug) {
  return td::td_api::make_object<td::td_api::internalLinkTypeGiftAuction>(slug);
}

static auto gift_collection(const td::string &owner_username, td::int32 collection_id) {
  return td::td_api::make_object<td::td_api::internalLinkTypeGiftCollection>(owner_username, collection_id);
}

static auto group_call(const td::string &slug) {
  return td::td_api::make_object<td::td_api::internalLinkTypeGroupCall>("tg:call?slug=" + slug);
}

static auto instant_view(const td::string &url, const td::string &fallback_url) {
  return td::td_api::make_object<td::td_api::internalLinkTypeInstantView>(url, fallback_url);
}

static auto invoice(const td::string &invoice_name) {
  return td::td_api::make_object<td::td_api::internalLinkTypeInvoice>(invoice_name);
}

static auto language_pack(const td::string &language_pack_name) {
  return td::td_api::make_object<td::td_api::internalLinkTypeLanguagePack>(language_pack_name);
}

static auto live_story(const td::string &poster_username) {
  return td::td_api::make_object<td::td_api::internalLinkTypeLiveStory>(poster_username);
}

static auto main_web_app(const td::string &bot_username, const td::string &start_parameter, bool is_compact,
                         bool is_full_screen) {
  return td::td_api::make_object<td::td_api::internalLinkTypeMainWebApp>(bot_username, start_parameter,
                                                                         web_app_open_mode(is_compact, is_full_screen));
}

static auto message(const td::string &url) {
  return td::td_api::make_object<td::td_api::internalLinkTypeMessage>(url);
}

static auto message_draft(td::string text, bool contains_url) {
  auto formatted_text = td::td_api::make_object<td::td_api::formattedText>();
  formatted_text->text_ = std::move(text);
  return td::td_api::make_object<td::td_api::internalLinkTypeMessageDraft>(std::move(formatted_text), contains_url);
}

static auto my_profile_page(const td::string &section) {
  return td::td_api::make_object<td::td_api::internalLinkTypeMyProfilePage>(section);
}

static auto new_channel_chat() {
  return td::td_api::make_object<td::td_api::internalLinkTypeNewChannelChat>();
}

static auto new_group_chat() {
  return td::td_api::make_object<td::td_api::internalLinkTypeNewGroupChat>();
}

static auto new_private_chat() {
  return td::td_api::make_object<td::td_api::internalLinkTypeNewPrivateChat>();
}

static auto new_story(td::td_api::object_ptr<td::td_api::StoryContentType> content_type) {
  return td::td_api::make_object<td::td_api::internalLinkTypeNewStory>(std::move(content_type));
}

static auto oauth(const td::string &url) {
  return td::td_api::make_object<td::td_api::internalLinkTypeOauth>(url);
}

static auto passport_data_request(td::int32 bot_user_id, const td::string &scope, const td::string &public_key,
                                  const td::string &nonce, const td::string &callback_url) {
  return td::td_api::make_object<td::td_api::internalLinkTypePassportDataRequest>(bot_user_id, scope, public_key, nonce,
                                                                                  callback_url);
}

static auto phone_number_confirmation(const td::string &hash, const td::string &phone_number) {
  return td::td_api::make_object<td::td_api::internalLinkTypePhoneNumberConfirmation>(hash, phone_number);
}

static auto premium_features_page(const td::string &referrer) {
  return td::td_api::make_object<td::td_api::internalLinkTypePremiumFeaturesPage>(referrer);
}

static auto premium_gift_code(const td::string &code) {
  return td::td_api::make_object<td::td_api::internalLinkTypePremiumGiftCode>(code);
}

static auto premium_gift_purchase(const td::string &referrer) {
  return td::td_api::make_object<td::td_api::internalLinkTypePremiumGiftPurchase>(referrer);
}

static auto proxy_mtproto(const td::string &server, td::int32 port, const td::string &secret) {
  return td::td_api::make_object<td::td_api::internalLinkTypeProxy>(td::td_api::make_object<td::td_api::proxy>(
      server, port, td::td_api::make_object<td::td_api::proxyTypeMtproto>(secret)));
}

static auto proxy_socks(const td::string &server, td::int32 port, const td::string &username,
                        const td::string &password) {
  return td::td_api::make_object<td::td_api::internalLinkTypeProxy>(td::td_api::make_object<td::td_api::proxy>(
      server, port, td::td_api::make_object<td::td_api::proxyTypeSocks5>(username, password)));
}

static auto public_chat(const td::string &chat_username, const td::string &draft_text = td::string(),
                        bool open_profile = false) {
  return td::td_api::make_object<td::td_api::internalLinkTypePublicChat>(chat_username, draft_text, open_profile);
}

static auto qr_code_authentication() {
  return td::td_api::make_object<td::td_api::internalLinkTypeQrCodeAuthentication>();
}

static auto request_managed_bot(const td::string &manager_bot_username, const td::string &suggested_bot_username,
                                const td::string &suggested_bot_name) {
  return td::td_api::make_object<td::td_api::internalLinkTypeRequestManagedBot>(
      manager_bot_username, suggested_bot_username, suggested_bot_name);
}

static auto restore_purchases() {
  return td::td_api::make_object<td::td_api::internalLinkTypeRestorePurchases>();
}

static auto saved_messages() {
  return td::td_api::make_object<td::td_api::internalLinkTypeSavedMessages>();
}

static auto search() {
  return td::td_api::make_object<td::td_api::internalLinkTypeSearch>();
}

static auto star_purchase(td::int64 star_count, const td::string &purpose) {
  return td::td_api::make_object<td::td_api::internalLinkTypeStarPurchase>(star_count, purpose);
}

static auto sticker_set(const td::string &sticker_set_name, bool expect_custom_emoji) {
  return td::td_api::make_object<td::td_api::internalLinkTypeStickerSet>(sticker_set_name, expect_custom_emoji);
}

static auto story(const td::string &poster_username, td::int32 story_id) {
  return td::td_api::make_object<td::td_api::internalLinkTypeStory>(poster_username, story_id);
}

static auto story_album(const td::string &owner_username, td::int32 story_album_id) {
  return td::td_api::make_object<td::td_api::internalLinkTypeStoryAlbum>(owner_username, story_album_id);
}

static auto text_composition_style(const td::string &style_name) {
  return td::td_api::make_object<td::td_api::internalLinkTypeTextCompositionStyle>(style_name);
}

static auto theme(const td::string &theme_name) {
  return td::td_api::make_object<td::td_api::internalLinkTypeTheme>(theme_name);
}

static auto unknown_deep_link(const td::string &link) {
  return td::td_api::make_object<td::td_api::internalLinkTypeUnknownDeepLink>(link);
}

static auto unsupported_proxy() {
  return td::td_api::make_object<td::td_api::internalLinkTypeProxy>(nullptr);
}

static auto upgraded_gift(const td::string &name) {
  return td::td_api::make_object<td::td_api::internalLinkTypeUpgradedGift>(name);
}

static auto user_phone_number(const td::string &phone_number, const td::string &draft_text = td::string(),
                              bool open_profile = false) {
  return td::td_api::make_object<td::td_api::internalLinkTypeUserPhoneNumber>('+' + phone_number, draft_text,
                                                                              open_profile);
}

static auto user_token(const td::string &token) {
  return td::td_api::make_object<td::td_api::internalLinkTypeUserToken>(token);
}

static auto video_chat(const td::string &chat_username, const td::string &invite_hash, bool is_live_stream) {
  return td::td_api::make_object<td::td_api::internalLinkTypeVideoChat>(chat_username, invite_hash, is_live_stream);
}

static auto web_app(const td::string &bot_username, const td::string &web_app_short_name,
                    const td::string &start_parameter, bool is_compact, bool is_full_screen) {
  return td::td_api::make_object<td::td_api::internalLinkTypeWebApp>(bot_username, web_app_short_name, start_parameter,
                                                                     web_app_open_mode(is_compact, is_full_screen));
}

TEST(Link, parse_internal_link_part1) {
  parse_internal_link("t.me/levlam/1", message("tg://resolve?domain=levlam&post=1"));
  parse_internal_link("telegram.me/levlam/1", message("tg://resolve?domain=levlam&post=1"));
  parse_internal_link("telegram.dog/levlam/1", message("tg://resolve?domain=levlam&post=1"));
  parse_internal_link("www.t.me/levlam/1", message("tg://resolve?domain=levlam&post=1"));
  parse_internal_link("www%2etelegram.me/levlam/1", message("tg://resolve?domain=levlam&post=1"));
  parse_internal_link("www%2Etelegram.dog/levlam/1", message("tg://resolve?domain=levlam&post=1"));
  parse_internal_link("www%252Etelegram.dog/levlam/1", nullptr);
  parse_internal_link("www.t.me/s/s/s/s/s/joinchat/1", nullptr);
  parse_internal_link("www.t.me/s/s/s/s/s/joinchat/a", chat_invite("a"));
  parse_internal_link("www.t.me/s/%73/%73/s/%73/joinchat/a", chat_invite("a"));
  parse_internal_link("http://t.me/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/s/joinchat/a", chat_invite("a"));
  parse_internal_link("http://t.me/levlam/1", message("tg://resolve?domain=levlam&post=1"));
  parse_internal_link("https://t.me/levlam/1", message("tg://resolve?domain=levlam&post=1"));
  parse_internal_link("hTtp://www.t.me:443/levlam/1", message("tg://resolve?domain=levlam&post=1"));
  parse_internal_link("httPs://t.me:80/levlam/1", message("tg://resolve?domain=levlam&post=1"));
  parse_internal_link("https://t.me:200/levlam/1", nullptr);
  parse_internal_link("http:t.me/levlam/1", nullptr);
  parse_internal_link("t.dog/levlam/1", nullptr);
  parse_internal_link("t.m/levlam/1", nullptr);
  parse_internal_link("t.men/levlam/1", nullptr);

  parse_internal_link("t.me/levlam?boos", public_chat("levlam"));
  parse_internal_link("telegram.me/levlam?booster", public_chat("levlam"));
  parse_internal_link("telegram.dog/levlam?boost", chat_boost("tg://boost?domain=levlam"));
  parse_internal_link("www.t.me/levlam?boost", chat_boost("tg://boost?domain=levlam"));
  parse_internal_link("t.me/c/l12345?boost", nullptr);
  parse_internal_link("t.me/c/12345l5431?boost", chat_boost("tg://boost?channel=12345"));
  parse_internal_link("t.me/c/12345?boost", chat_boost("tg://boost?channel=12345"));
  parse_internal_link("t.me/c/123456789012?boost", chat_boost("tg://boost?channel=123456789012"));
  parse_internal_link("t.me/c/123456789012?boost=12312&domain=123", chat_boost("tg://boost?channel=123456789012"));

  parse_internal_link("t.me/boost/a/12345", story_album("boost", 12345));
  parse_internal_link("t.me/boost/c/12345", gift_collection("boost", 12345));
  parse_internal_link("t.me/boost/s/12345", story("boost", 12345));
  parse_internal_link("t.me/boost/s", chat_boost("tg://boost?domain=s"));
  parse_internal_link("t.me/boost/12", message("tg://resolve?domain=boost&post=12"));
  parse_internal_link("t.me/boost?cc=1#c=1", public_chat("boost"));
  parse_internal_link("t.me/boost?c=-1", public_chat("boost"));
  parse_internal_link("t.me/boost?c=12telegram", chat_boost("tg://boost?channel=12"));
  parse_internal_link("t.me/bOoSt?c=12telegram", chat_boost("tg://boost?channel=12"));

  parse_internal_link("tg:boost?domain=username/12345&single", chat_boost("tg://boost?domain=username%2F12345"));
  parse_internal_link("tg:boost?domain=username&channel=12345", chat_boost("tg://boost?domain=username"));
  parse_internal_link("tg:boost?channel=12345&domain=username", chat_boost("tg://boost?domain=username"));
  parse_internal_link("tg:boost?channel=12345", chat_boost("tg://boost?channel=12345"));

  parse_internal_link("tg:resolve?domain=username&post=12345&single",
                      message("tg://resolve?domain=username&post=12345&single"));
  parse_internal_link("tg:resolve?domain=username&post=12345&single&startattach=1&attach=test",
                      message("tg://resolve?domain=username&post=12345&single"));
  parse_internal_link("tg:resolve?domain=user%31name&post=%312345&single&comment=456&t=789&single&thread=123%20%31",
                      message("tg://resolve?domain=user1name&post=12345&single&thread=123%201&comment=456&t=789"));
  parse_internal_link("TG://resolve?domain=username&post=12345&single&voicechat=aasd",
                      message("tg://resolve?domain=username&post=12345&single"));
  parse_internal_link("TG://test@resolve?domain=username&post=12345&single", nullptr);
  parse_internal_link("tg:resolve:80?domain=username&post=12345&single", nullptr);
  parse_internal_link("tg:http://resolve?domain=username&post=12345&single", nullptr);
  parse_internal_link("tg:https://resolve?domain=username&post=12345&single", nullptr);
  parse_internal_link("tg:resolve?domain=&post=12345&single",
                      unknown_deep_link("tg://resolve?domain=&post=12345&single"));
  parse_internal_link("tg:resolve?domain=telegram&post=&single", public_chat("telegram"));
  parse_internal_link("tg:resolve?domain=123456&post=&single",
                      unknown_deep_link("tg://resolve?domain=123456&post=&single"));
  parse_internal_link("tg:resolve?domain=telegram&startattach", attachment_menu_bot(nullptr, nullptr, "telegram", ""));
  parse_internal_link("tg:resolve?domain=telegram&startattach=1",
                      attachment_menu_bot(nullptr, nullptr, "telegram", "1"));
  parse_internal_link("tg:resolve?domain=telegram&startattach=1&choose=cats+dogs",
                      attachment_menu_bot(nullptr, nullptr, "telegram", "1"));
  parse_internal_link("tg:resolve?domain=telegram&startattach=1&choose=users",
                      attachment_menu_bot(target_chat_chosen(true, false, false, false), nullptr, "telegram", "1"));
  parse_internal_link("tg:resolve?domain=telegram&startattach=*&choose=users",
                      attachment_menu_bot(target_chat_chosen(true, false, false, false), nullptr, "telegram", ""));
  parse_internal_link("tg:resolve?domain=telegram&startattach=1&choose=bots",
                      attachment_menu_bot(target_chat_chosen(false, true, false, false), nullptr, "telegram", "1"));
  parse_internal_link("tg:resolve?domain=telegram&startattach=1&choose=groups",
                      attachment_menu_bot(target_chat_chosen(false, false, true, false), nullptr, "telegram", "1"));
  parse_internal_link("tg:resolve?domain=telegram&startattach=1&choose=channels",
                      attachment_menu_bot(target_chat_chosen(false, false, false, true), nullptr, "telegram", "1"));
  parse_internal_link("tg:resolve?domain=telegram&startattach=1&choose=users+channels",
                      attachment_menu_bot(target_chat_chosen(true, false, false, true), nullptr, "telegram", "1"));
  parse_internal_link("tg:resolve?domain=telegram&attach=&startattach",
                      attachment_menu_bot(nullptr, nullptr, "telegram", ""));
  parse_internal_link("tg:resolve?domain=telegram&attach=&startattach=1",
                      attachment_menu_bot(nullptr, nullptr, "telegram", "1"));
  parse_internal_link("tg:resolve?domain=telegram&attach=test&startattach",
                      attachment_menu_bot(nullptr, public_chat("telegram"), "test", ""));
  parse_internal_link("tg:resolve?domain=telegram&attach=test&startattach=1",
                      attachment_menu_bot(nullptr, public_chat("telegram"), "test", "1"));
  parse_internal_link("tg:resolve?domain=username&profile=12&asd", public_chat("username", "", true));
  parse_internal_link("tg:resolve?domain=username&profile&text=@asd", public_chat("username", " @asd", true));
  parse_internal_link("tg:resolve?domain=telegram&attach=test%30&startattach=1",
                      attachment_menu_bot(nullptr, public_chat("telegram"), "test0", "1"));
  parse_internal_link("tg:resolve?domain=telegram&attach=%30test&startattach=1", public_chat("telegram"));
  parse_internal_link("tg:resolve?domain=telegram&attach=test%30&startattach=%31",
                      attachment_menu_bot(nullptr, public_chat("telegram"), "test0", "1"));
  parse_internal_link("tg:resolve?domain=telegram&attach=test%30&startattach=*",
                      attachment_menu_bot(nullptr, public_chat("telegram"), "test0", ""));

  parse_internal_link("tg:resolve?phone=1", user_phone_number("1"));
  parse_internal_link("tg:resolve?phone=+1", user_phone_number("1"));
  parse_internal_link("tg:resolve?phone=123456", user_phone_number("123456"));
  parse_internal_link("tg:resolve?phone=123456&startattach", user_phone_number("123456"));
  parse_internal_link("tg:resolve?phone=123456&startattach=123", user_phone_number("123456"));
  parse_internal_link("tg:resolve?phone=123456&attach=", user_phone_number("123456"));
  parse_internal_link("tg:resolve?phone=123456&attach=&startattach", user_phone_number("123456"));
  parse_internal_link("tg:resolve?phone=123456&attach=&startattach=123", user_phone_number("123456"));
  parse_internal_link("tg:resolve?phone=123456&attach=test",
                      attachment_menu_bot(nullptr, user_phone_number("123456"), "test", ""));
  parse_internal_link("tg:resolve?phone=+123456&attach=test",
                      attachment_menu_bot(nullptr, user_phone_number("123456"), "test", ""));
  parse_internal_link("tg:resolve?phone=++123456&attach=test",
                      unknown_deep_link("tg://resolve?phone=++123456&attach=test"));
  parse_internal_link("tg:resolve?phone=123456&attach=test&startattach&choose=users",
                      attachment_menu_bot(nullptr, user_phone_number("123456"), "test", ""));
  parse_internal_link("tg:resolve?phone=123456&attach=test&startattach=123",
                      attachment_menu_bot(nullptr, user_phone_number("123456"), "test", "123"));
  parse_internal_link("tg:resolve?phone=01234567890123456789012345678912",
                      user_phone_number("01234567890123456789012345678912"));
  parse_internal_link("tg:resolve?phone=012345678901234567890123456789123",
                      unknown_deep_link("tg://resolve?phone=012345678901234567890123456789123"));
  parse_internal_link("tg:resolve?phone=", unknown_deep_link("tg://resolve?phone="));
  parse_internal_link("tg:resolve?phone=+123", user_phone_number("123"));
  parse_internal_link("tg:resolve?phone=123456 ", unknown_deep_link("tg://resolve?phone=123456 "));
  parse_internal_link("tg:resolve?domain=telegram&text=asd", public_chat("telegram", "asd"));
  parse_internal_link("tg:resolve?phone=12345678901&text=asd", user_phone_number("12345678901", "asd"));
  parse_internal_link("tg:resolve?domain=telegram&text=@asd", public_chat("telegram", " @asd"));
  parse_internal_link("tg:resolve?phone=12345678901&text=@asd", user_phone_number("12345678901", " @asd"));
  parse_internal_link("tg:resolve?domain=telegram&text=1%A02", public_chat("telegram"));
  parse_internal_link("tg:resolve?phone=12345678901&text=1%A02", user_phone_number("12345678901"));
  parse_internal_link("tg:resolve?phone=123456&profile", user_phone_number("123456", "", true));
  parse_internal_link("tg:resolve?phone=123456&profile&text=@asd", user_phone_number("123456", " @asd", true));
  parse_internal_link("tg:resolve?phone=123456&attach=test%30&startattach=1",
                      attachment_menu_bot(nullptr, user_phone_number("123456"), "test0", "1"));
  parse_internal_link("tg:resolve?phone=123456&attach=%30test&startattach=1", user_phone_number("123456"));
  parse_internal_link("tg:resolve?phone=123456&attach=test%30&startattach=%31",
                      attachment_menu_bot(nullptr, user_phone_number("123456"), "test0", "1"));
  parse_internal_link("tg:resolve?phone=123456&attach=test%30&startattach=*",
                      attachment_menu_bot(nullptr, user_phone_number("123456"), "test0", ""));

  parse_internal_link("tg:resolve?domain=oauth&startapp=12345", oauth("tg://resolve?domain=oauth&startapp=12345"));
  parse_internal_link("tg:resolve?domain=oauth&startapp=%312345&token=asd",
                      oauth("tg://resolve?domain=oauth&startapp=12345"));
  parse_internal_link("tg:resolve?domain=oauth&startapp=", main_web_app("oauth", "", false, false));
  parse_internal_link("tg:resolve?domain=oauth", public_chat("oauth"));
  parse_internal_link("tg:oauth?token=12345", oauth("tg://oauth?token=12345"));
  parse_internal_link("tg:oauth?token=%312345&startapp=1231", oauth("tg://oauth?token=12345"));
  parse_internal_link("tg:oauth?token=", unknown_deep_link("tg://oauth?token="));

  parse_internal_link("tg:contact?token=1", user_token("1"));
  parse_internal_link("tg:contact?token=123456", user_token("123456"));
  parse_internal_link("tg:contact?token=123456&startattach", user_token("123456"));
  parse_internal_link("tg:contact?token=123456&startattach=123", user_token("123456"));
  parse_internal_link("tg:contact?token=123456&attach=", user_token("123456"));
  parse_internal_link("tg:contact?token=123456&attach=&startattach", user_token("123456"));
  parse_internal_link("tg:contact?token=123456&attach=&startattach=123", user_token("123456"));
  parse_internal_link("tg:contact?token=01234567890123456789012345678912",
                      user_token("01234567890123456789012345678912"));
  parse_internal_link("tg:contact?token=012345678901234567890123456789123",
                      user_token("012345678901234567890123456789123"));
  parse_internal_link("tg:contact?token=", unknown_deep_link("tg://contact?token="));
  parse_internal_link("tg:contact?token=+123", user_token(" 123"));
  parse_internal_link("tg:contact?token=%30123", user_token("0123"));
  parse_internal_link("tg:contact?token=%29123", user_token(")123"));
  parse_internal_link("tg:contact?token=%2F123", user_token("/123"));
  parse_internal_link("tg:contact?token=%FF123", unknown_deep_link("tg://contact?token=%FF123"));

  parse_internal_link("tg:nft?slug=1", upgraded_gift("1"));
  parse_internal_link("tg:nft?slug=123456", upgraded_gift("123456"));
  parse_internal_link("tg:nft?slug=123456&startattach", upgraded_gift("123456"));
  parse_internal_link("tg:nft?slug=123456&startattach=123", upgraded_gift("123456"));
  parse_internal_link("tg:nft?slug=123456&attach=", upgraded_gift("123456"));
  parse_internal_link("tg:nft?slug=123456/789&attach=&startattach", upgraded_gift("123456/789"));
  parse_internal_link("tg:nft?slug=123456&attach=&startattach=123", upgraded_gift("123456"));
  parse_internal_link("tg:nft?slug=01234567890123456789012345678912",
                      upgraded_gift("01234567890123456789012345678912"));
  parse_internal_link("tg:nft?slug=012345678901234567890123456789123",
                      upgraded_gift("012345678901234567890123456789123"));
  parse_internal_link("tg:nft?slug=", unknown_deep_link("tg://nft?slug="));
  parse_internal_link("tg:nft?slug=+123", upgraded_gift(" 123"));
  parse_internal_link("tg:nft?slug=%FF", unknown_deep_link("tg://nft?slug=%FF"));

  parse_internal_link("t.me/username/12345?single", message("tg://resolve?domain=username&post=12345&single"));
  parse_internal_link("t.me/username/12345?asdasd", message("tg://resolve?domain=username&post=12345"));
  parse_internal_link("t.me/username/12345", message("tg://resolve?domain=username&post=12345"));
  parse_internal_link("t.me/username/12345/", message("tg://resolve?domain=username&post=12345"));
  parse_internal_link("t.me/username/12345#asdasd", message("tg://resolve?domain=username&post=12345"));
  parse_internal_link("t.me/username/12345//?voicechat=&single",
                      message("tg://resolve?domain=username&post=12345&single"));
  parse_internal_link("t.me/username/12345/asdasd//asd/asd/asd/?single",
                      message("tg://resolve?domain=username&post=12345&single"));
  parse_internal_link("t.me/username/12345/67890/asdasd//asd/asd/asd/?single",
                      message("tg://resolve?domain=username&post=67890&single&thread=12345"));
  parse_internal_link("t.me/username/1asdasdas/asdasd//asd/asd/asd/?single",
                      message("tg://resolve?domain=username&post=1&single"));
  parse_internal_link("t.me/username/0", public_chat("username"));
  parse_internal_link("t.me/username/-12345", public_chat("username"));
  parse_internal_link("t.me//12345?single", nullptr);
  parse_internal_link("https://telegram.dog/telegram/?single", public_chat("telegram"));
  parse_internal_link("t.me/username?startattach", attachment_menu_bot(nullptr, nullptr, "username", ""));
  parse_internal_link("t.me/username?startattach=1", attachment_menu_bot(nullptr, nullptr, "username", "1"));
  parse_internal_link("t.me/username?startattach=1&choose=cats+dogs",
                      attachment_menu_bot(nullptr, nullptr, "username", "1"));
  parse_internal_link("t.me/username?startattach=1&choose=users",
                      attachment_menu_bot(target_chat_chosen(true, false, false, false), nullptr, "username", "1"));
  parse_internal_link("t.me/username?startattach=1*&choose=users",
                      attachment_menu_bot(target_chat_chosen(true, false, false, false), nullptr, "username", ""));
  parse_internal_link("t.me/username?startattach=1&choose=bots",
                      attachment_menu_bot(target_chat_chosen(false, true, false, false), nullptr, "username", "1"));
  parse_internal_link("t.me/username?startattach=1&choose=groups",
                      attachment_menu_bot(target_chat_chosen(false, false, true, false), nullptr, "username", "1"));
  parse_internal_link("t.me/username?startattach=1&choose=channels",
                      attachment_menu_bot(target_chat_chosen(false, false, false, true), nullptr, "username", "1"));
  parse_internal_link("t.me/username?startattach=1&choose=bots+groups",
                      attachment_menu_bot(target_chat_chosen(false, true, true, false), nullptr, "username", "1"));
  parse_internal_link("t.me/username?attach=", public_chat("username"));
  parse_internal_link("t.me/username?attach=&startattach", attachment_menu_bot(nullptr, nullptr, "username", ""));
  parse_internal_link("t.me/username?attach=&startattach=1", attachment_menu_bot(nullptr, nullptr, "username", "1"));
  parse_internal_link("t.me/username?attach=bot", attachment_menu_bot(nullptr, public_chat("username"), "bot", ""));
  parse_internal_link("t.me/username?attach=bot&startattach",
                      attachment_menu_bot(nullptr, public_chat("username"), "bot", ""));
  parse_internal_link("t.me/username?attach=bot&startattach=1&choose=users",
                      attachment_menu_bot(nullptr, public_chat("username"), "bot", "1"));
  parse_internal_link("t.me/username?asd&profile=12", public_chat("username", "", true));
  parse_internal_link("t.me/username?profile&text=@asd", public_chat("username", " @asd", true));
  parse_internal_link("t.me/username?attach=bot%30", attachment_menu_bot(nullptr, public_chat("username"), "bot0", ""));
  parse_internal_link("t.me/username?attach=%30bot&startattach=1", public_chat("username"));
  parse_internal_link("t.me/username?attach=bot%30&startattach=%31",
                      attachment_menu_bot(nullptr, public_chat("username"), "bot0", "1"));
  parse_internal_link("t.me/username?attach=bot%30&startattach=*",
                      attachment_menu_bot(nullptr, public_chat("username"), "bot0", ""));

  parse_internal_link("tg:privatepost?domain=username/12345&single",
                      unknown_deep_link("tg://privatepost?domain=username/12345&single"));
  parse_internal_link("tg:privatepost?channel=username/12345&single",
                      unknown_deep_link("tg://privatepost?channel=username/12345&single"));
  parse_internal_link("tg:privatepost?channel=username&post=12345",
                      message("tg://privatepost?channel=username&post=12345"));

  parse_internal_link("t.me/c/12345?single", nullptr);
  parse_internal_link("t.me/c/1/c?single", nullptr);
  parse_internal_link("t.me/c/c/1?single", nullptr);
  parse_internal_link("t.me/c//1?single", nullptr);
  parse_internal_link("t.me/c/12345/123", message("tg://privatepost?channel=12345&post=123"));
  parse_internal_link("t.me/c/12345/123?single", message("tg://privatepost?channel=12345&post=123&single"));
  parse_internal_link("t.me/c/12345/123/asd/asd////?single", message("tg://privatepost?channel=12345&post=123&single"));
  parse_internal_link("t.me/c/12345/123/456/asd/asd////?single",
                      message("tg://privatepost?channel=12345&post=456&single&thread=123"));
  parse_internal_link("t.me/c/%312345/%3123?comment=456&t=789&single&thread=123%20%31",
                      message("tg://privatepost?channel=12345&post=123&single&thread=123%201&comment=456&t=789"));
  parse_internal_link("t.me/c/%312345/%3123?comment=456&t=2h3m101s&single&thread=123%20%31",
                      message("tg://privatepost?channel=12345&post=123&single&thread=123%201&comment=456&t=2h3m101s"));

  parse_internal_link("tg:bg?color=111111#asdasd", background("111111"));
  parse_internal_link("tg:bg?color=11111%31", background("111111"));
  parse_internal_link("tg:bg?color=11111%20", background("11111%20"));
  parse_internal_link("tg:bg?gradient=111111-222222", background("111111-222222"));
  parse_internal_link("tg:bg?rotation=180%20&gradient=111111-222222%20",
                      background("111111-222222%20?rotation=180%20"));
  parse_internal_link("tg:bg?gradient=111111~222222", background("111111~222222"));
  parse_internal_link("tg:bg?gradient=abacaba", background("abacaba"));
  parse_internal_link("tg:bg?slug=test#asdasd", background("test"));
  parse_internal_link("tg:bg?slug=test&mode=blur", background("test?mode=blur"));
  parse_internal_link("tg:bg?slug=test&mode=blur&text=1", background("test?mode=blur"));
  parse_internal_link("tg:bg?slug=test&mode=blur&mode=1", background("test?mode=blur"));
  parse_internal_link("tg:bg?slug=test&mode=blur&rotation=4&intensity=2&bg_color=3",
                      background("test?mode=blur&intensity=2&bg_color=3&rotation=4"));
  parse_internal_link("tg:bg?mode=blur&&slug=test&intensity=2&bg_color=3",
                      background("test?mode=blur&intensity=2&bg_color=3"));
  parse_internal_link("tg:bg?mode=blur&intensity=2&bg_color=3",
                      unknown_deep_link("tg://bg?mode=blur&intensity=2&bg_color=3"));

  parse_internal_link("tg:bg?color=111111#asdasd", background("111111"));
  parse_internal_link("tg:bg?color=11111%31", background("111111"));
  parse_internal_link("tg:bg?color=11111%20", background("11111%20"));
  parse_internal_link("tg:bg?gradient=111111-222222", background("111111-222222"));
  parse_internal_link("tg:bg?rotation=180%20&gradient=111111-222222%20",
                      background("111111-222222%20?rotation=180%20"));
  parse_internal_link("tg:bg?gradient=111111~222222&mode=blur", background("111111~222222"));
  parse_internal_link("tg:bg?gradient=abacaba", background("abacaba"));
  parse_internal_link("tg:bg?slug=test#asdasd", background("test"));
  parse_internal_link("tg:bg?slug=test&mode=blur", background("test?mode=blur"));
  parse_internal_link("tg:bg?slug=test&mode=blur&text=1", background("test?mode=blur"));
  parse_internal_link("tg:bg?slug=test&mode=blur&mode=1", background("test?mode=blur"));
  parse_internal_link("tg:bg?slug=test&mode=blur&rotation=4&intensity=2&bg_color=3",
                      background("test?mode=blur&intensity=2&bg_color=3&rotation=4"));
  parse_internal_link("tg:bg?mode=blur&&slug=test&intensity=2&bg_color=3",
                      background("test?mode=blur&intensity=2&bg_color=3"));
  parse_internal_link("tg:bg?mode=blur&intensity=2&bg_color=3",
                      unknown_deep_link("tg://bg?mode=blur&intensity=2&bg_color=3"));

  parse_internal_link("%54.me/bg/111111#asdasd", background("111111"));
  parse_internal_link("t.me/bg/11111%31", background("111111"));
  parse_internal_link("t.me/bg/11111%20", background("11111%20"));
  parse_internal_link("t.me/bg/111111-222222", background("111111-222222"));
  parse_internal_link("t.me/bg/111111-222222%20?rotation=180%20", background("111111-222222%20?rotation=180%20"));
  parse_internal_link("t.me/bg/111111~222222", background("111111~222222"));
  parse_internal_link("t.me/bg/abacaba", background("abacaba"));
  parse_internal_link("t.me/Bg/abacaba", web_app("Bg", "abacaba", "", false, false));
  parse_internal_link("t.me/bg/111111~222222#asdasd", background("111111~222222"));
  parse_internal_link("t.me/bg/111111~222222?mode=blur", background("111111~222222"));
  parse_internal_link("t.me/bg/111111~222222?mode=blur&text=1", background("111111~222222"));
  parse_internal_link("t.me/bg/111111~222222?mode=blur&mode=1", background("111111~222222"));
  parse_internal_link("t.me/bg/testteststststststststststststs?mode=blur&rotation=4&intensity=2&bg_color=3&mode=1",
                      background("testteststststststststststststs?mode=blur&intensity=2&bg_color=3&rotation=4"));
  parse_internal_link("t.me/%62g/testteststststststststststststs/?mode=blur+motion&&&intensity=2&bg_color=3",
                      background("testteststststststststststststs?mode=blur%20motion&intensity=2&bg_color=3"));
  parse_internal_link("t.me/bg//", nullptr);
  parse_internal_link("t.me/bg/%20/", background("%20"));
  parse_internal_link("t.me/bg/", nullptr);
}

TEST(Link, parse_internal_link_part2) {
  parse_internal_link("t.me/invoice?slug=abcdef", nullptr);
  parse_internal_link("t.me/invoice", nullptr);
  parse_internal_link("t.me/invoice/", nullptr);
  parse_internal_link("t.me/invoice//abcdef", nullptr);
  parse_internal_link("t.me/invoice?/abcdef", nullptr);
  parse_internal_link("t.me/invoice/?abcdef", nullptr);
  parse_internal_link("t.me/invoice/#abcdef", nullptr);
  parse_internal_link("t.me/invoice/abacaba", invoice("abacaba"));
  parse_internal_link("t.me/invoice/aba%20aba", invoice("aba aba"));
  parse_internal_link("t.me/invoice/123456a", invoice("123456a"));
  parse_internal_link("t.me/invoice/12345678901", invoice("12345678901"));
  parse_internal_link("t.me/invoice/123456", invoice("123456"));
  parse_internal_link("t.me/invoice/123456/123123/12/31/a/s//21w/?asdas#test", invoice("123456"));
  parse_internal_link("t.me/invoice/123%FF456", nullptr);

  parse_internal_link("t.me/$?slug=abcdef", nullptr);
  parse_internal_link("t.me/$", nullptr);
  parse_internal_link("t.me/$/abcdef", nullptr);
  parse_internal_link("t.me/$?/abcdef", nullptr);
  parse_internal_link("t.me/$?abcdef", nullptr);
  parse_internal_link("t.me/$#abcdef", nullptr);
  parse_internal_link("t.me/$abacaba", invoice("abacaba"));
  parse_internal_link("t.me/$aba%20aba", invoice("aba aba"));
  parse_internal_link("t.me/$123456a", invoice("123456a"));
  parse_internal_link("t.me/$12345678901", invoice("12345678901"));
  parse_internal_link("t.me/$123456", invoice("123456"));
  parse_internal_link("t.me/%24123456", invoice("123456"));
  parse_internal_link("t.me/$123456/123123/12/31/a/s//21w/?asdas#test", invoice("123456"));
  parse_internal_link("t.me/$aba%FFaba", nullptr);

  parse_internal_link("tg:invoice?slug=abcdef", invoice("abcdef"));
  parse_internal_link("tg:invoice?slug=abc%30ef", invoice("abc0ef"));
  parse_internal_link("tg://invoice?slug=", unknown_deep_link("tg://invoice?slug="));
  parse_internal_link("tg:invoice?slug=abc%FFef", unknown_deep_link("tg://invoice?slug=abc%FFef"));

  parse_internal_link("t.me/giftcode?slug=abcdef", nullptr);
  parse_internal_link("t.me/giftcode", nullptr);
  parse_internal_link("t.me/giftcode/", nullptr);
  parse_internal_link("t.me/giftcode//abcdef", nullptr);
  parse_internal_link("t.me/giftcode?/abcdef", nullptr);
  parse_internal_link("t.me/giftcode/?abcdef", nullptr);
  parse_internal_link("t.me/giftcode/#abcdef", nullptr);
  parse_internal_link("t.me/giftcode/abacaba", premium_gift_code("abacaba"));
  parse_internal_link("t.me/giftcode/aba%20aba", premium_gift_code("aba aba"));
  parse_internal_link("t.me/giftcode/123456a", premium_gift_code("123456a"));
  parse_internal_link("t.me/giftcode/12345678901", premium_gift_code("12345678901"));
  parse_internal_link("t.me/giftcode/123456", premium_gift_code("123456"));
  parse_internal_link("t.me/giftcode/123456/123123/12/31/a/s//21w/?asdas#test", premium_gift_code("123456"));
  parse_internal_link("t.me/giftcode/123%FF456", nullptr);

  parse_internal_link("tg:giftcode?slug=abcdef", premium_gift_code("abcdef"));
  parse_internal_link("tg:giftcode?slug=abc%30ef", premium_gift_code("abc0ef"));
  parse_internal_link("tg://giftcode?slug=", unknown_deep_link("tg://giftcode?slug="));
  parse_internal_link("tg://giftcode?slug=%FF", unknown_deep_link("tg://giftcode?slug=%FF"));

  parse_internal_link("t.me/m?slug=abcdef", nullptr);
  parse_internal_link("t.me/m", nullptr);
  parse_internal_link("t.me/m/", nullptr);
  parse_internal_link("t.me/m//abcdef", nullptr);
  parse_internal_link("t.me/m?/abcdef", nullptr);
  parse_internal_link("t.me/m/?abcdef", nullptr);
  parse_internal_link("t.me/m/#abcdef", nullptr);
  parse_internal_link("t.me/m/abacaba", business_chat("abacaba"));
  parse_internal_link("t.me/m/aba%20aba", business_chat("aba aba"));
  parse_internal_link("t.me/m/123456a", business_chat("123456a"));
  parse_internal_link("t.me/m/12345678901", business_chat("12345678901"));
  parse_internal_link("t.me/m/123456", business_chat("123456"));
  parse_internal_link("t.me/m/123456/123123/12/31/a/s//21w/?asdas#test", business_chat("123456"));
  parse_internal_link("t.me/m/aba%FFaba", nullptr);

  parse_internal_link("tg:message?slug=abcdef", business_chat("abcdef"));
  parse_internal_link("tg:message?slug=abc%30ef", business_chat("abc0ef"));
  parse_internal_link("tg://message?slug=", unknown_deep_link("tg://message?slug="));
  parse_internal_link("tg:message?slug=abc%FFef", unknown_deep_link("tg://message?slug=abc%FFef"));

  parse_internal_link("tg:share?url=google.com&text=text#asdasd", message_draft("google.com\ntext", true));
  parse_internal_link("tg:share?url=google.com&text=", message_draft("google.com", false));
  parse_internal_link("tg:share?url=&text=google.com", message_draft("google.com", false));
  parse_internal_link("tg:msg_url?url=google.com&text=text", message_draft("google.com\ntext", true));
  parse_internal_link("tg:msg_url?url=google.com&text=", message_draft("google.com", false));
  parse_internal_link("tg:msg_url?url=&text=google.com", message_draft("google.com", false));
  parse_internal_link("tg:msg?url=google.com&text=text", message_draft("google.com\ntext", true));
  parse_internal_link("tg:msg?url=google.com&text=", message_draft("google.com", false));
  parse_internal_link("tg:msg?url=&text=google.com", message_draft("google.com", false));
  parse_internal_link("tg:msg?url=&text=\n\n\n\n\n\n\n\n", nullptr);
  parse_internal_link("tg:msg?url=%20\n&text=", nullptr);
  parse_internal_link("tg:msg?url=%20\n&text=google.com", message_draft("google.com", false));
  parse_internal_link("tg:msg?url=@&text=", message_draft(" @", false));
  parse_internal_link("tg:msg?url=&text=@", message_draft(" @", false));
  parse_internal_link("tg:msg?url=@&text=@", message_draft(" @\n@", true));
  parse_internal_link("tg:msg?url=%FF&text=1", nullptr);

  parse_internal_link("https://t.me/share?url=google.com&text=text#asdasd", nullptr);
  parse_internal_link("https://t.me/share/?url=google.com&text=text#asdasd", nullptr);
  parse_internal_link("https://t.me/share/abc?url=google.com&text=text#asdasd", nullptr);
  parse_internal_link("https://t.me/share/embed?url=google.com&text=text#asdasd", nullptr);
  parse_internal_link("https://t.me/share/url?url=google.com&text=text#asdasd",
                      message_draft("google.com\ntext", true));
  parse_internal_link("https://t.me/share/url?url=google.com&text=", message_draft("google.com", false));
  parse_internal_link("https://t.me/share/url?url=&text=google.com", message_draft("google.com", false));
  parse_internal_link("https://t.me/msg/url?url=google.com&text=text", message_draft("google.com\ntext", true));
  parse_internal_link("https://t.me/msg/url?url=google.com&text=", message_draft("google.com", false));
  parse_internal_link("https://t.me/msg/url?url=&text=google.com", message_draft("google.com", false));
  parse_internal_link("https://t.me/msg/url?url=google.com&text=text", message_draft("google.com\ntext", true));
  parse_internal_link("https://t.me/msg/url?url=google.com&text=", message_draft("google.com", false));
  parse_internal_link("https://t.me/msg/url?url=&text=google.com", message_draft("google.com", false));
  parse_internal_link("https://t.me/msg/url?url=&text=\n\n\n\n\n\n\n\n", nullptr);
  parse_internal_link("https://t.me/msg/url?url=%20%0A&text=", nullptr);
  parse_internal_link("https://t.me/msg/url?url=%20%0A&text=google.com", message_draft("google.com", false));
  parse_internal_link("https://t.me/msg/url?url=@&text=", message_draft(" @", false));
  parse_internal_link("https://t.me/msg/url?url=&text=@", message_draft(" @", false));
  parse_internal_link("https://t.me/msg/url?url=@&text=@", message_draft(" @\n@", true));
  parse_internal_link("https://t.me/msg/url?url=%FF&text=1", nullptr);

  parse_internal_link("tg:login?codec=12345", unknown_deep_link("tg://login?codec=12345"));
  parse_internal_link("tg:login", unknown_deep_link("tg://login"));
  parse_internal_link("tg:login?code=abacaba", authentication_code("abacaba"));
  parse_internal_link("tg:login?code=123456", authentication_code("123456"));
  parse_internal_link("tg:login?code=%2F123456", authentication_code("/123456"));
  parse_internal_link("tg:login?code=%FF123456", unknown_deep_link("tg://login?code=%FF123456"));

  parse_internal_link("t.me/login?codec=12345", nullptr);
  parse_internal_link("t.me/login", nullptr);
  parse_internal_link("t.me/login/", nullptr);
  parse_internal_link("t.me/login//12345", nullptr);
  parse_internal_link("t.me/login?/12345", nullptr);
  parse_internal_link("t.me/login/?12345", nullptr);
  parse_internal_link("t.me/login/#12345", nullptr);
  parse_internal_link("t.me/login/abacaba", authentication_code("abacaba"));
  parse_internal_link("t.me/login/aba%20aba", authentication_code("aba aba"));
  parse_internal_link("t.me/login/123456a", authentication_code("123456a"));
  parse_internal_link("t.me/login/12345678901", authentication_code("12345678901"));
  parse_internal_link("t.me/login/123456", authentication_code("123456"));
  parse_internal_link("t.me/login/123456/123123/12/31/a/s//21w/?asdas#test", authentication_code("123456"));
  parse_internal_link("t.me/login/%2F123456", authentication_code("/123456"));
  parse_internal_link("t.me/login/%FF123456", nullptr);

  parse_internal_link("tg:login?token=abacaba", qr_code_authentication());
  parse_internal_link("tg:login?token=", unknown_deep_link("tg://login?token="));

  parse_internal_link("tg:restore_purchases?token=abacaba", restore_purchases());
  parse_internal_link("tg:restore_purchases?#", restore_purchases());
  parse_internal_link("tg:restore_purchases/?#", restore_purchases());
  parse_internal_link("tg:restore_purchases", restore_purchases());
  parse_internal_link("tg:restore_purchase", unknown_deep_link("tg://restore_purchase"));
  parse_internal_link("tg:restore_purchasess", unknown_deep_link("tg://restore_purchasess"));
  parse_internal_link("tg:restore_purchases/test?#", unknown_deep_link("tg://restore_purchases/test?"));

  parse_internal_link("tg:settings/saved-messages?token=abacaba", saved_messages());
  parse_internal_link("tg:settings/saved-messages?#", saved_messages());
  parse_internal_link("tg:settings/saved-messages/?#", saved_messages());
  parse_internal_link("tg:settings/saved-messages", saved_messages());
  parse_internal_link("tg:settings/saved-message", settings());
  parse_internal_link("tg:settings/saved-messagess", settings());
  parse_internal_link("tg:settings/saved-messages/test?#", saved_messages());

  parse_internal_link("tg://settings/calls", calls_page(""));
  parse_internal_link("tg://settings/calls/asdasd", calls_page(""));
  parse_internal_link("tg://settings/calls/all", calls_page("all"));
  parse_internal_link("tg://settings/calls/edit", calls_page("edit"));
  parse_internal_link("tg://settings/calls/all", calls_page("all"));
  parse_internal_link("tg://settings/calls/start-call", calls_page("start-call"));

  parse_internal_link("tg://settings/my-profile", my_profile_page(""));
  parse_internal_link("tg://settings/my-profile/asdasd", my_profile_page(""));
  parse_internal_link("tg://settings/my-profile/posts", my_profile_page("posts"));
  parse_internal_link("tg://settings/my-profile/posts/add-album", my_profile_page("posts/add-album"));
  parse_internal_link("tg://settings/my-profile/archived-posts", my_profile_page("archived-posts"));

  parse_internal_link("tg://chats/search/", search());
  parse_internal_link("tg://chats/edit", chat_selection());
  parse_internal_link("tg://chats/emoji-status", edit_profile_settings("emoji-status"));

  parse_internal_link("tg://contacts", contacts_page(""));
  parse_internal_link("tg://contacts/asdasd", contacts_page(""));
  parse_internal_link("tg://contacts/new", contacts_page("new"));
  parse_internal_link("tg://contacts/edit", contacts_page(""));
  parse_internal_link("tg://contacts/search", contacts_page("search"));
  parse_internal_link("tg://contacts/search/search", contacts_page(""));
  parse_internal_link("tg://contacts/manage", contacts_page("manage"));

  parse_internal_link("tg://new", new_private_chat());
  parse_internal_link("tg://new/", new_private_chat());
  parse_internal_link("tg://new/asd", unknown_deep_link("tg://new/asd"));
  parse_internal_link("tg://new/group", new_group_chat());
  parse_internal_link("tg://new/group/", new_group_chat());
  parse_internal_link("tg://new/channel", new_channel_chat());
  parse_internal_link("tg://new/channel/", new_channel_chat());

  parse_internal_link("tg://post", new_story(nullptr));
  parse_internal_link("tg://post/photo", new_story(td::td_api::make_object<td::td_api::storyContentTypePhoto>()));
  parse_internal_link("tg://post/video", new_story(td::td_api::make_object<td::td_api::storyContentTypeVideo>()));
  parse_internal_link("tg://post/live", new_story(td::td_api::make_object<td::td_api::storyContentTypeLive>()));
  parse_internal_link("tg://post/photos",
                      new_story(td::td_api::make_object<td::td_api::storyContentTypeUnsupported>()));

  parse_internal_link("t.me/joinchat?invite=abcdef", nullptr);
  parse_internal_link("t.me/joinchat", nullptr);
  parse_internal_link("t.me/joinchat/", nullptr);
  parse_internal_link("t.me/joinchat//abcdef", nullptr);
  parse_internal_link("t.me/joinchat?/abcdef", nullptr);
  parse_internal_link("t.me/joinchat/?abcdef", nullptr);
  parse_internal_link("t.me/joinchat/#abcdef", nullptr);
  parse_internal_link("t.me/joinchat/abacaba", chat_invite("abacaba"));
  parse_internal_link("t.me/joinchat/aba%20aba", nullptr);
  parse_internal_link("t.me/joinchat/aba%30aba", chat_invite("aba0aba"));
  parse_internal_link("t.me/joinchat/123456a", chat_invite("123456a"));
  parse_internal_link("t.me/joinchat/12345678901", nullptr);
  parse_internal_link("t.me/joinchat/123456", nullptr);
  parse_internal_link("t.me/joinchat/123456/123123/12/31/a/s//21w/?asdas#test", nullptr);
  parse_internal_link("t.me/joinchat/12345678901a", chat_invite("12345678901a"));
  parse_internal_link("t.me/joinchat/123456a", chat_invite("123456a"));
  parse_internal_link("t.me/joinchat/123456a/123123/12/31/a/s//21w/?asdas#test", chat_invite("123456a"));

  parse_internal_link("t.me/+?invite=abcdef", nullptr);
  parse_internal_link("t.me/+a", chat_invite("a"));
  parse_internal_link("t.me/+", nullptr);
  parse_internal_link("t.me/+/abcdef", nullptr);
  parse_internal_link("t.me/ ?/abcdef", nullptr);
  parse_internal_link("t.me/+?abcdef", nullptr);
  parse_internal_link("t.me/+#abcdef", nullptr);
  parse_internal_link("t.me/ abacaba", chat_invite("abacaba"));
  parse_internal_link("t.me/+aba%20aba", nullptr);
  parse_internal_link("t.me/+aba%30aba", chat_invite("aba0aba"));
  parse_internal_link("t.me/+123456a", chat_invite("123456a"));
  parse_internal_link("t.me/%2012345678901", user_phone_number("12345678901"));
  parse_internal_link("t.me/+123456", user_phone_number("123456"));
  parse_internal_link("t.me/ 123456/123123/12/31/a/s//21w/?asdas#test", user_phone_number("123456"));
  parse_internal_link("t.me/ /123456/123123/12/31/a/s//21w/?asdas#test", nullptr);
  parse_internal_link("t.me/+123456?startattach", user_phone_number("123456"));
  parse_internal_link("t.me/+123456?startattach=1", user_phone_number("123456"));
  parse_internal_link("t.me/+123456?attach=", user_phone_number("123456"));
  parse_internal_link("t.me/+123456?attach=&startattach", user_phone_number("123456"));
  parse_internal_link("t.me/+123456?attach=&startattach=1", user_phone_number("123456"));
  parse_internal_link("t.me/+123456?attach=bot", attachment_menu_bot(nullptr, user_phone_number("123456"), "bot", ""));
  parse_internal_link("t.me/+123456?attach=bot&startattach&profile",
                      attachment_menu_bot(nullptr, user_phone_number("123456"), "bot", ""));
  parse_internal_link("t.me/+123456?attach=bot&startattach=1",
                      attachment_menu_bot(nullptr, user_phone_number("123456"), "bot", "1"));
  parse_internal_link("t.me/+123456?profile", user_phone_number("123456", "", true));
  parse_internal_link("t.me/+123456?profile&text=@asd", user_phone_number("123456", " @asd", true));
  parse_internal_link("t.me/+123456?attach=bot%30",
                      attachment_menu_bot(nullptr, user_phone_number("123456"), "bot0", ""));
  parse_internal_link("t.me/+123456?attach=%30bot&startattach=1", user_phone_number("123456"));
  parse_internal_link("t.me/+123456?attach=bot%30&startattach=%31",
                      attachment_menu_bot(nullptr, user_phone_number("123456"), "bot0", "1"));
  parse_internal_link("t.me/+123456?attach=bot%30&startattach=*",
                      attachment_menu_bot(nullptr, user_phone_number("123456"), "bot0", ""));

  parse_internal_link("telegram.t.me?text=asd", public_chat("telegram", "asd"));
  parse_internal_link("t.me/%2012345678901?text=asd", user_phone_number("12345678901", "asd"));
  parse_internal_link("t.me/telegram?text=@asd", public_chat("telegram", " @asd"));
  parse_internal_link("t.me/%2012345678901?text=@asd", user_phone_number("12345678901", " @asd"));
  parse_internal_link("t.me/telegram?text=1%A02", public_chat("telegram"));
  parse_internal_link("t.me/%2012345678901?text=1%A02", user_phone_number("12345678901"));

  parse_internal_link("t.me/addlist?invite=abcdef", nullptr);
  parse_internal_link("t.me/addlist", nullptr);
  parse_internal_link("t.me/addlist/", nullptr);
  parse_internal_link("t.me/addlist//abcdef", nullptr);
  parse_internal_link("t.me/addlist?/abcdef", nullptr);
  parse_internal_link("t.me/addlist/?abcdef", nullptr);
  parse_internal_link("t.me/addlist/#abcdef", nullptr);
  parse_internal_link("t.me/addlist/abacaba", chat_folder_invite("abacaba"));
  parse_internal_link("t.me/addlist/aba%20aba", nullptr);
  parse_internal_link("t.me/addlist/aba%30aba", chat_folder_invite("aba0aba"));
  parse_internal_link("t.me/addlist/123456a", chat_folder_invite("123456a"));
  parse_internal_link("t.me/addlist/12345678901", chat_folder_invite("12345678901"));
  parse_internal_link("t.me/addlist/123456", chat_folder_invite("123456"));
  parse_internal_link("t.me/addlist/123456/123123/12/31/a/s//21w/?asdas#test", chat_folder_invite("123456"));
  parse_internal_link("t.me/addlist/12345678901a", chat_folder_invite("12345678901a"));
  parse_internal_link("t.me/addlist/123456a", chat_folder_invite("123456a"));
  parse_internal_link("t.me/addlist/123456a/123123/12/31/a/s//21w/?asdas#test", chat_folder_invite("123456a"));

  parse_internal_link("t.me/auction?slug=abcdef", nullptr);
  parse_internal_link("t.me/auction", nullptr);
  parse_internal_link("t.me/auction/", nullptr);
  parse_internal_link("t.me/auction//abcdef", nullptr);
  parse_internal_link("t.me/auction?/abcdef", nullptr);
  parse_internal_link("t.me/auction/?abcdef", nullptr);
  parse_internal_link("t.me/auction/#abcdef", nullptr);
  parse_internal_link("t.me/auction/abacaba", gift_auction("abacaba"));
  parse_internal_link("t.me/auction/aba%20aba", gift_auction("aba aba"));
  parse_internal_link("t.me/auction/aba%30aba", gift_auction("aba0aba"));
  parse_internal_link("t.me/auction/123456a", gift_auction("123456a"));
  parse_internal_link("t.me/auction/12345678901", gift_auction("12345678901"));
  parse_internal_link("t.me/auction/123456", gift_auction("123456"));
  parse_internal_link("t.me/auction/123456/123123/12/31/a/s//21w/?asdas#test", gift_auction("123456"));
  parse_internal_link("t.me/auction/12345678901a", gift_auction("12345678901a"));
  parse_internal_link("t.me/auction/123456a", gift_auction("123456a"));
  parse_internal_link("t.me/auction/123456a/123123/12/31/a/s//21w/?asdas#test", gift_auction("123456a"));

  parse_internal_link("t.me/call?invite=abcdef", nullptr);
  parse_internal_link("t.me/call", nullptr);
  parse_internal_link("t.me/call/", nullptr);
  parse_internal_link("t.me/call//abcdef", nullptr);
  parse_internal_link("t.me/call?/abcdef", nullptr);
  parse_internal_link("t.me/call/?abcdef", nullptr);
  parse_internal_link("t.me/call/#abcdef", nullptr);
  parse_internal_link("t.me/call/abacaba", group_call("abacaba"));
  parse_internal_link("t.me/call/aba%20aba", nullptr);
  parse_internal_link("t.me/call/aba%30aba", group_call("aba0aba"));
  parse_internal_link("t.me/call/123456a", group_call("123456a"));
  parse_internal_link("t.me/call/12345678901", group_call("12345678901"));
  parse_internal_link("t.me/call/123456", group_call("123456"));
  parse_internal_link("t.me/call/123456/123123/12/31/a/s//21w/?asdas#test", group_call("123456"));
  parse_internal_link("t.me/call/12345678901a", group_call("12345678901a"));
  parse_internal_link("t.me/call/123456a", group_call("123456a"));
  parse_internal_link("t.me/call/123456a/123123/12/31/a/s//21w/?asdas#test", group_call("123456a"));

  parse_internal_link("t.me/contact/startattach/adasd", user_token("startattach"));
  parse_internal_link("t.me/contact/startattach", user_token("startattach"));
  parse_internal_link("t.me/contact/startattach=1", user_token("startattach=1"));
  parse_internal_link("t.me/contact/", nullptr);
  parse_internal_link("t.me/contact/?attach=&startattach", nullptr);
  parse_internal_link("t.me/contact/%30123", user_token("0123"));
  parse_internal_link("t.me/contact/%29123", user_token(")123"));
  parse_internal_link("t.me/contact/%2F123", user_token("/123"));
  parse_internal_link("t.me/contact/%FF123", nullptr);

  parse_internal_link("t.me/nft/startattach/adasd", upgraded_gift("startattach/adasd"));
  parse_internal_link("t.me/nft/startattach", upgraded_gift("startattach"));
  parse_internal_link("t.me/nft/startattach=1", upgraded_gift("startattach=1"));
  parse_internal_link("t.me/nft/", nullptr);
  parse_internal_link("t.me/nft/?attach=&startattach", nullptr);
  parse_internal_link("t.me/nft/startattach%FF", nullptr);

  parse_internal_link("tg:join?invite=abcdef", chat_invite("abcdef"));
  parse_internal_link("tg:join?invite=abc%20def", unknown_deep_link("tg://join?invite=abc%20def"));
  parse_internal_link("tg://join?invite=abc%30def", chat_invite("abc0def"));
  parse_internal_link("tg:join?invite=", unknown_deep_link("tg://join?invite="));

  parse_internal_link("tg:addlist?slug=abcdef", chat_folder_invite("abcdef"));
  parse_internal_link("tg:addlist?slug=abc%20def", unknown_deep_link("tg://addlist?slug=abc%20def"));
  parse_internal_link("tg://addlist?slug=abc%30def", chat_folder_invite("abc0def"));
  parse_internal_link("tg:addlist?slug=", unknown_deep_link("tg://addlist?slug="));

  parse_internal_link("tg:stargift_auction?slug=abcdef", gift_auction("abcdef"));
  parse_internal_link("tg:stargift_auction?slug=abc%20def", gift_auction("abc def"));
  parse_internal_link("tg://stargift_auction?slug=abc%30def", gift_auction("abc0def"));
  parse_internal_link("tg:stargift_auction?slug=", unknown_deep_link("tg://stargift_auction?slug="));

  parse_internal_link("tg:call?slug=abcdef", group_call("abcdef"));
  parse_internal_link("tg:call?slug=abc%20def", unknown_deep_link("tg://call?slug=abc%20def"));
  parse_internal_link("tg://call?slug=abc%30def", group_call("abc0def"));
  parse_internal_link("tg:call?slug=", unknown_deep_link("tg://call?slug="));

  parse_internal_link("t.me/addstickers?set=abcdef", nullptr);
  parse_internal_link("t.me/addstickers", nullptr);
  parse_internal_link("t.me/addstickers/", nullptr);
  parse_internal_link("t.me/addstickers//abcdef", nullptr);
  parse_internal_link("t.me/addstickers?/abcdef", nullptr);
  parse_internal_link("t.me/addstickers/?abcdef", nullptr);
  parse_internal_link("t.me/addstickers/#abcdef", nullptr);
  parse_internal_link("t.me/addstickers/abacaba", sticker_set("abacaba", false));
  parse_internal_link("t.me/addstickers/aba%20aba", nullptr);
  parse_internal_link("t.me/addstickers/123456a", sticker_set("123456a", false));
  parse_internal_link("t.me/addstickers/12345678901", sticker_set("12345678901", false));
  parse_internal_link("t.me/addstickers/123456", sticker_set("123456", false));
  parse_internal_link("t.me/addstickers/123456/123123/12/31/a/s//21w/?asdas#test", sticker_set("123456", false));

  parse_internal_link("tg:addstickers?set=abcdef", sticker_set("abcdef", false));
  parse_internal_link("tg:addstickers?set=abc%30ef", sticker_set("abc0ef", false));
  parse_internal_link("tg:addstickers?set=abc%2Fef", unknown_deep_link("tg://addstickers?set=abc%2Fef"));
  parse_internal_link("tg://addstickers?set=", unknown_deep_link("tg://addstickers?set="));

  parse_internal_link("t.me/addemoji?set=abcdef", nullptr);
  parse_internal_link("t.me/addemoji", nullptr);
  parse_internal_link("t.me/addemoji/", nullptr);
  parse_internal_link("t.me/addemoji//abcdef", nullptr);
  parse_internal_link("t.me/addemoji?/abcdef", nullptr);
  parse_internal_link("t.me/addemoji/?abcdef", nullptr);
  parse_internal_link("t.me/addemoji/#abcdef", nullptr);
  parse_internal_link("t.me/addemoji/abacaba", sticker_set("abacaba", true));
  parse_internal_link("t.me/addemoji/aba%20aba", nullptr);
  parse_internal_link("t.me/addemoji/123456a", sticker_set("123456a", true));
  parse_internal_link("t.me/addemoji/12345678901", sticker_set("12345678901", true));
  parse_internal_link("t.me/addemoji/123456", sticker_set("123456", true));
  parse_internal_link("t.me/addemoji/123456/123123/12/31/a/s//21w/?asdas#test", sticker_set("123456", true));

  parse_internal_link("tg:addemoji?set=abcdef", sticker_set("abcdef", true));
  parse_internal_link("tg:addemoji?set=abc%30ef", sticker_set("abc0ef", true));
  parse_internal_link("tg:addemoji?set=abc%2Fef", unknown_deep_link("tg://addemoji?set=abc%2Fef"));
  parse_internal_link("tg://addemoji?set=", unknown_deep_link("tg://addemoji?set="));
}

TEST(Link, parse_internal_link_part3) {
  parse_internal_link("t.me/confirmphone?hash=abc%30ef&phone=", nullptr);
  parse_internal_link("t.me/confirmphone/123456/123123/12/31/a/s//21w/?hash=abc%30ef&phone=123456789",
                      phone_number_confirmation("abc0ef", "123456789"));
  parse_internal_link("t.me/confirmphone?hash=abc%30ef&phone=123456789",
                      phone_number_confirmation("abc0ef", "123456789"));
  parse_internal_link("t.me/confirmphone?hash=abc%2Fef&phone=123456789", nullptr);
  parse_internal_link("t.me/confirmphone?hash=&phone=123456789", nullptr);
  parse_internal_link("t.me/confirmphone?hash=abc%30ef&phone=+123456789", nullptr);

  parse_internal_link("tg:confirmphone?hash=abc%30ef&phone=",
                      unknown_deep_link("tg://confirmphone?hash=abc%30ef&phone="));
  parse_internal_link("tg:confirmphone?hash=abc%30ef&phone=123456789",
                      phone_number_confirmation("abc0ef", "123456789"));
  parse_internal_link("tg://confirmphone?hash=123&phone=123456789123456789",
                      phone_number_confirmation("123", "123456789123456789"));
  parse_internal_link("tg://confirmphone?hash=&phone=123456789123456789",
                      unknown_deep_link("tg://confirmphone?hash=&phone=123456789123456789"));
  parse_internal_link("tg://confirmphone?hash=123456789123456789&phone=",
                      unknown_deep_link("tg://confirmphone?hash=123456789123456789&phone="));
  parse_internal_link("tg://confirmphone?hash=abc%2Fef&phone=123456789",
                      unknown_deep_link("tg://confirmphone?hash=abc%2Fef&phone=123456789"));
  parse_internal_link("tg://confirmphone?hash=&phone=123456789",
                      unknown_deep_link("tg://confirmphone?hash=&phone=123456789"));
  parse_internal_link("tg://confirmphone?hash=abc%30ef&phone=+123456789",
                      unknown_deep_link("tg://confirmphone?hash=abc%30ef&phone=+123456789"));

  parse_internal_link("t.me/setlanguage?lang=abcdef", nullptr);
  parse_internal_link("t.me/setlanguage", nullptr);
  parse_internal_link("t.me/setlanguage/", nullptr);
  parse_internal_link("t.me/setlanguage//abcdef", nullptr);
  parse_internal_link("t.me/setlanguage?/abcdef", nullptr);
  parse_internal_link("t.me/setlanguage/?abcdef", nullptr);
  parse_internal_link("t.me/setlanguage/#abcdef", nullptr);
  parse_internal_link("t.me/setlanguage/abacaba", language_pack("abacaba"));
  parse_internal_link("t.me/setlanguage/aba%30ab-a", language_pack("aba0ab-a"));
  parse_internal_link("t.me/setlanguage/aba%20ab-a", nullptr);
  parse_internal_link("t.me/setlanguage/aba%2Faba", nullptr);
  parse_internal_link("t.me/setlanguage/123456a", language_pack("123456a"));
  parse_internal_link("t.me/setlanguage/12345678901", language_pack("12345678901"));
  parse_internal_link("t.me/setlanguage/123456", language_pack("123456"));
  parse_internal_link("t.me/setlanguage/123456/123123/12/31/a/s//21w/?asdas#test", language_pack("123456"));

  parse_internal_link("tg:setlanguage?lang=abcdef", language_pack("abcdef"));
  parse_internal_link("tg:setlanguage?lang=abc%30e-f", language_pack("abc0e-f"));
  parse_internal_link("tg:setlanguage?lang=abc%20ef", unknown_deep_link("tg://setlanguage?lang=abc%20ef"));
  parse_internal_link("tg:setlanguage?lang=abc%2Fef", unknown_deep_link("tg://setlanguage?lang=abc%2Fef"));
  parse_internal_link("tg://setlanguage?lang=", unknown_deep_link("tg://setlanguage?lang="));

  parse_internal_link(
      "http://telegram.dog/iv?url=https://telegram.org&rhash=abcdef&test=1&tg_rhash=1",
      instant_view("https://t.me/iv?url=https%3A%2F%2Ftelegram.org&rhash=abcdef", "https://telegram.org"));
  parse_internal_link("t.me/iva?url=https://telegram.org&rhash=abcdef", public_chat("iva"));
  parse_internal_link("t.me/iv?url=&rhash=abcdef", nullptr);
  parse_internal_link("t.me/iv?url=https://telegram.org&rhash=",
                      instant_view("https://t.me/iv?url=https%3A%2F%2Ftelegram.org&rhash", "https://telegram.org"));
  parse_internal_link("t.me/iv//////?url=https://telegram.org&rhash=",
                      instant_view("https://t.me/iv?url=https%3A%2F%2Ftelegram.org&rhash", "https://telegram.org"));
  parse_internal_link("t.me/iv/////1/?url=https://telegram.org&rhash=", nullptr);
  parse_internal_link("t.me/iv", nullptr);
  parse_internal_link("t.me/iv?#url=https://telegram.org&rhash=abcdef", nullptr);
  parse_internal_link("tg:iv?url=https://telegram.org&rhash=abcdef",
                      unknown_deep_link("tg://iv?url=https://telegram.org&rhash=abcdef"));

  parse_internal_link("t.me/addtheme?slug=abcdef", nullptr);
  parse_internal_link("t.me/addtheme", nullptr);
  parse_internal_link("t.me/addtheme/", nullptr);
  parse_internal_link("t.me/addtheme//abcdef", nullptr);
  parse_internal_link("t.me/addtheme?/abcdef", nullptr);
  parse_internal_link("t.me/addtheme/?abcdef", nullptr);
  parse_internal_link("t.me/addtheme/#abcdef", nullptr);
  parse_internal_link("t.me/addtheme/abacaba", theme("abacaba"));
  parse_internal_link("t.me/addtheme/aba%20aba", theme("aba aba"));
  parse_internal_link("t.me/addtheme/aba%2Faba", theme("aba/aba"));
  parse_internal_link("t.me/addtheme/123456a", theme("123456a"));
  parse_internal_link("t.me/addtheme/12345678901", theme("12345678901"));
  parse_internal_link("t.me/addtheme/123456", theme("123456"));
  parse_internal_link("t.me/addtheme/123456/123123/12/31/a/s//21w/?asdas#test", theme("123456"));

  parse_internal_link("tg:addtheme?slug=abcdef", theme("abcdef"));
  parse_internal_link("tg:addtheme?slug=abc%30ef", theme("abc0ef"));
  parse_internal_link("tg:addtheme?slug=abc%20ef", theme("abc ef"));
  parse_internal_link("tg:addtheme?slug=abc%2Fef", theme("abc/ef"));
  parse_internal_link("tg://addtheme?slug=", unknown_deep_link("tg://addtheme?slug="));

  parse_internal_link("t.me/addstyle?slug=abcdefabc", nullptr);
  parse_internal_link("t.me/addstyle", nullptr);
  parse_internal_link("t.me/addstyle/", nullptr);
  parse_internal_link("t.me/addstyle//abcdefabc", nullptr);
  parse_internal_link("t.me/addstyle?/abcdefabc", nullptr);
  parse_internal_link("t.me/addstyle/?abcdefabc", nullptr);
  parse_internal_link("t.me/addstyle/#abcdefabc", nullptr);
  parse_internal_link("t.me/addstyle/abacaba", nullptr);
  parse_internal_link("t.me/addstyle/abacabaabc", text_composition_style("abacabaabc"));
  parse_internal_link("t.me/addstyle/aba%30abaabc", text_composition_style("aba0abaabc"));
  parse_internal_link("t.me/addstyle/aba%2Fabaabc", nullptr);
  parse_internal_link("t.me/addstyle/123456aabc", text_composition_style("123456aabc"));
  parse_internal_link("t.me/addstyle/12345678901", text_composition_style("12345678901"));
  parse_internal_link("t.me/addstyle/123456abc", text_composition_style("123456abc"));
  parse_internal_link("t.me/addstyle/123456abc/123123/12/31/a/s//21w/?asdas#test", text_composition_style("123456abc"));

  parse_internal_link("tg:addstyle?slug=abcdefabc", text_composition_style("abcdefabc"));
  parse_internal_link("tg:addstyle?slug=abc%30efabc", text_composition_style("abc0efabc"));
  parse_internal_link("tg:addstyle?slug=abc%20efabc", unknown_deep_link("tg://addstyle?slug=abc%20efabc"));
  parse_internal_link("tg:addstyle?slug=abc%2Fefabc", unknown_deep_link("tg://addstyle?slug=abc%2Fefabc"));
  parse_internal_link("tg://addstyle?slug=", unknown_deep_link("tg://addstyle?slug="));

  parse_internal_link("t.me/proxy?server=1.2.3.4&port=80&secret=1234567890abcdef1234567890ABCDEF",
                      proxy_mtproto("1.2.3.4", 80, "1234567890abcdef1234567890abcdef"));
  parse_internal_link("t.me/proxy?server=1.2.3.4&port=80adasdas&secret=1234567890abcdef1234567890ABCDEF",
                      proxy_mtproto("1.2.3.4", 80, "1234567890abcdef1234567890abcdef"));
  parse_internal_link("t.me/proxy?server=1.2.3.4&port=adasdas&secret=1234567890abcdef1234567890ABCDEF",
                      unsupported_proxy());
  parse_internal_link("t.me/proxy?server=1.2.3.4&port=65536&secret=1234567890abcdef1234567890ABCDEF",
                      unsupported_proxy());
  parse_internal_link("t.me/proxy?server=google.com&port=8%30&secret=", unsupported_proxy());
  parse_internal_link("t.me/proxy?server=google.com&port=8%30&secret=12", unsupported_proxy());
  parse_internal_link("t.me/proxy?server=google.com&port=8%30&secret=1234567890abcdef1234567890ABCDEF",
                      proxy_mtproto("google.com", 80, "1234567890abcdef1234567890abcdef"));
  parse_internal_link("t.me/proxy?server=google.com&port=8%30&secret=dd1234567890abcdef1234567890ABCDEF",
                      proxy_mtproto("google.com", 80, "dd1234567890abcdef1234567890abcdef"));
  parse_internal_link("t.me/proxy?server=google.com&port=8%30&secret=de1234567890abcdef1234567890ABCDEF",
                      unsupported_proxy());
  parse_internal_link("t.me/proxy?server=google.com&port=8%30&secret=ee1234567890abcdef1234567890ABCDEF",
                      unsupported_proxy());
  parse_internal_link("t.me/proxy?server=google.com&port=8%30&secret=ee1234567890abcdef1234567890ABCDEF0",
                      unsupported_proxy());
  parse_internal_link("t.me/proxy?server=google.com&port=8%30&secret=ee1234567890abcdef1234567890ABCDEF%30%30",
                      proxy_mtproto("google.com", 80, "7hI0VniQq83vEjRWeJCrze8A"));
  parse_internal_link(
      "t.me/proxy?server=google.com&port=8%30&secret=ee1234567890abcdef1234567890ABCDEF010101010101010101",
      proxy_mtproto("google.com", 80, "7hI0VniQq83vEjRWeJCrze8BAQEBAQEBAQE"));
  parse_internal_link("t.me/proxy?server=google.com&port=8%30&secret=7tAAAAAAAAAAAAAAAAAAAAAAAAcuZ29vZ2xlLmNvbQ",
                      proxy_mtproto("google.com", 80, "7tAAAAAAAAAAAAAAAAAAAAAAAAcuZ29vZ2xlLmNvbQ"));
  parse_internal_link(
      "t.me/proxy?server=google.com&port=8%30&secret=7ge9Ug57SJOnMe8J%2BSj5pyZnaXRodWIuY29t",
      proxy_mtproto("google.com", 80, "7ge9Ug57SJOnMe8J-Sj5pyZnaXRodWIuY29t"));  // invalid, but accepted
  parse_internal_link(
      "t.me/proxy?server=google.com&port=8%30&secret=7ge9Ug57SJOnMe8J%2FSj5pyZnaXRodWIuY29t",
      proxy_mtproto("google.com", 80, "7ge9Ug57SJOnMe8J_Sj5pyZnaXRodWIuY29t"));  // invalid, but accepted
  parse_internal_link("t.me/proxy?server=google.com&port=8%30&secret=7ge9Ug57SJOnMe8J-Sj5pyZnaXRodWIuY29t",
                      proxy_mtproto("google.com", 80, "7ge9Ug57SJOnMe8J-Sj5pyZnaXRodWIuY29t"));
  parse_internal_link("t.me/proxy?server=google.com&port=8%30&secret=7ge9Ug57SJOnMe8J_Sj5pyZnaXRodWIuY29t",
                      proxy_mtproto("google.com", 80, "7ge9Ug57SJOnMe8J_Sj5pyZnaXRodWIuY29t"));
  parse_internal_link("t.me/proxy", unsupported_proxy());
  parse_internal_link("t.me/proxy?server=&port=80&secret=1234567890abcdef1234567890ABCDEF", unsupported_proxy());
  parse_internal_link("t.me/proxy?server=%FF&port=80&secret=1234567890abcdef1234567890ABCDEF", unsupported_proxy());

  parse_internal_link("tg:proxy?server=1.2.3.4&port=80&secret=1234567890abcdef1234567890ABCDEF",
                      proxy_mtproto("1.2.3.4", 80, "1234567890abcdef1234567890abcdef"));
  parse_internal_link("tg:proxy?server=1.2.3.4&port=80adasdas&secret=1234567890abcdef1234567890ABCDEF",
                      proxy_mtproto("1.2.3.4", 80, "1234567890abcdef1234567890abcdef"));
  parse_internal_link("tg:proxy?server=1.2.3.4&port=adasdas&secret=1234567890abcdef1234567890ABCDEF",
                      unsupported_proxy());
  parse_internal_link("tg:proxy?server=1.2.3.4&port=65536&secret=1234567890abcdef1234567890ABCDEF",
                      unsupported_proxy());
  parse_internal_link("tg:proxy?server=google.com&port=8%30&secret=1234567890abcdef1234567890ABCDEF",
                      proxy_mtproto("google.com", 80, "1234567890abcdef1234567890abcdef"));
  parse_internal_link("tg:proxy?server=google.com&port=8%30&secret=dd1234567890abcdef1234567890ABCDEF",
                      proxy_mtproto("google.com", 80, "dd1234567890abcdef1234567890abcdef"));
  parse_internal_link("tg:proxy?server=google.com&port=8%30&secret=de1234567890abcdef1234567890ABCDEF",
                      unsupported_proxy());
  parse_internal_link("tg:proxy", unsupported_proxy());
  parse_internal_link("tg:proxy?server=&port=80&secret=1234567890abcdef1234567890ABCDEF", unsupported_proxy());
  parse_internal_link("tg:proxy?server=%FF&port=80&secret=1234567890abcdef1234567890ABCDEF", unsupported_proxy());

  parse_internal_link("t.me/socks?server=1.2.3.4&port=80", proxy_socks("1.2.3.4", 80, "", ""));
  parse_internal_link("t.me/socks?server=1.2.3.4&port=80adasdas", proxy_socks("1.2.3.4", 80, "", ""));
  parse_internal_link("t.me/socks?server=1.2.3.4&port=adasdas", unsupported_proxy());
  parse_internal_link("t.me/socks?server=1.2.3.4&port=65536", unsupported_proxy());
  parse_internal_link("t.me/socks?server=google.com&port=8%30", proxy_socks("google.com", 80, "", ""));
  parse_internal_link("t.me/socks?server=google.com&port=8%30&user=1&pass=", proxy_socks("google.com", 80, "1", ""));
  parse_internal_link("t.me/socks?server=google.com&port=8%30&user=&pass=2", proxy_socks("google.com", 80, "", "2"));
  parse_internal_link("t.me/socks?server=google.com&port=80&user=1&pass=2", proxy_socks("google.com", 80, "1", "2"));
  parse_internal_link("t.me/socks", unsupported_proxy());
  parse_internal_link("t.me/socks?server=&port=80", unsupported_proxy());
  parse_internal_link("t.me/socks?server=google.com&port=80&user=%FF&pass=", unsupported_proxy());
  parse_internal_link("t.me/socks?server=google.com&port=80&user=&pass=%FF", unsupported_proxy());

  parse_internal_link("tg:socks?server=1.2.3.4&port=80", proxy_socks("1.2.3.4", 80, "", ""));
  parse_internal_link("tg:socks?server=1.2.3.4&port=80adasdas", proxy_socks("1.2.3.4", 80, "", ""));
  parse_internal_link("tg:socks?server=1.2.3.4&port=adasdas", unsupported_proxy());
  parse_internal_link("tg:socks?server=1.2.3.4&port=65536", unsupported_proxy());
  parse_internal_link("tg:socks?server=google.com&port=8%30", proxy_socks("google.com", 80, "", ""));
  parse_internal_link("tg:socks?server=google.com&port=8%30&user=1&pass=", proxy_socks("google.com", 80, "1", ""));
  parse_internal_link("tg:socks?server=google.com&port=8%30&user=&pass=2", proxy_socks("google.com", 80, "", "2"));
  parse_internal_link("tg:socks?server=google.com&port=80&user=1&pass=2", proxy_socks("google.com", 80, "1", "2"));
  parse_internal_link("tg:socks", unsupported_proxy());
  parse_internal_link("tg:socks?server=&port=80", unsupported_proxy());
  parse_internal_link("tg:socks?server=google.com&port=80&user=%FF&pass=", unsupported_proxy());
  parse_internal_link("tg:socks?server=google.com&port=80&user=&pass=%FF", unsupported_proxy());

  parse_internal_link("tg:resolve?domain=username&voice%63hat=aasdasd", video_chat("username", "aasdasd", false));
  parse_internal_link("tg:resolve?domain=username&video%63hat=aasdasd", video_chat("username", "aasdasd", false));
  parse_internal_link("tg:resolve?domain=username&livestream=aasdasd", video_chat("username", "aasdasd", true));
  parse_internal_link("TG://resolve?domain=username&voicechat=", video_chat("username", "", false));
  parse_internal_link("TG://test@resolve?domain=username&voicechat=", nullptr);
  parse_internal_link("tg:resolve:80?domain=username&voicechat=", nullptr);
  parse_internal_link("tg:http://resolve?domain=username&voicechat=", nullptr);
  parse_internal_link("tg:https://resolve?domain=username&voicechat=", nullptr);
  parse_internal_link("tg:resolve?domain=&voicechat=", unknown_deep_link("tg://resolve?domain=&voicechat="));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&voicechat=%30", video_chat("telegram", "0", false));
  parse_internal_link("tg:resolve?domain=username&livestream=*", public_chat("username"));
  parse_internal_link("tg:resolve?domain=username&livestream=%30", video_chat("username", "0", true));

  parse_internal_link("t.me/username/0/a//s/as?voicechat=", video_chat("username", "", false));
  parse_internal_link("t.me/username/0/a//s/as?videochat=2", video_chat("username", "2", false));
  parse_internal_link("t.me/username/0/a//s/as?livestream=3", video_chat("username", "3", true));
  parse_internal_link("t.me/username/aasdas/2?test=1&voicechat=#12312", video_chat("username", "", false));
  parse_internal_link("t.me/username/0?voicechat=", video_chat("username", "", false));
  parse_internal_link("t.me/username/-1?voicechat=asdasd", video_chat("username", "asdasd", false));
  parse_internal_link("t.me/username?voicechat=", video_chat("username", "", false));
  parse_internal_link("t.me/username#voicechat=asdas", public_chat("username"));
  parse_internal_link("t.me//username?voicechat=", nullptr);
  parse_internal_link("https://telegram.dog/tele%63ram?voi%63e%63hat=t%63st", video_chat("telecram", "tcst", false));
  parse_internal_link("t.me/username/0/a//s/as?livestream=%30", video_chat("username", "0", true));
  parse_internal_link("t.me/username/0/a//s/as?livestream=*", public_chat("username"));

  parse_internal_link("tg:resolve?domain=username&start=aasdasd", bot_start("username", "aasdasd"));
  parse_internal_link("TG://resolve?domain=username&start=", bot_start("username", ""));
  parse_internal_link("TG://test@resolve?domain=username&start=", nullptr);
  parse_internal_link("tg:resolve:80?domain=username&start=", nullptr);
  parse_internal_link("tg:http://resolve?domain=username&start=", nullptr);
  parse_internal_link("tg:https://resolve?domain=username&start=", nullptr);
  parse_internal_link("tg:resolve?domain=&start=", unknown_deep_link("tg://resolve?domain=&start="));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&start=%30", bot_start("telegram", "0"));

  parse_internal_link("t.me/username/0/a//s/as?start=", bot_start("username", ""));
  parse_internal_link("t.me/username/aasdas/2?test=1&start=#12312", bot_start("username", ""));
  parse_internal_link("t.me/username/0?start=", bot_start("username", ""));
  parse_internal_link("t.me/username/-1?start=asdasd", bot_start("username", "asdasd"));
  parse_internal_link("t.me/username?start=", bot_start("username", ""));
  parse_internal_link("t.me/username#start=asdas", public_chat("username"));
  parse_internal_link("t.me//username?start=", nullptr);
  parse_internal_link("https://telegram.dog/tele%63ram?start=t%63st", bot_start("telecram", "tcst"));

  parse_internal_link("tg:resolve?domain=username&start=_tgr_", bot_start("username", "_tgr_"));
  parse_internal_link("tg:resolve?domain=username&start=_tgr_aSd", chat_affiliate_program("username", "aSd"));
  parse_internal_link("tg:resolve?domain=username&start=_tgr_a%30Sd", chat_affiliate_program("username", "a0Sd"));

  parse_internal_link("t.me/username/0/a//s/as?start=_tgr_", bot_start("username", "_tgr_"));
  parse_internal_link("t.me/username/0/a//s/as?start=_tgr_aSd", chat_affiliate_program("username", "aSd"));
  parse_internal_link("t.me/username/0/a//s/as?start=_tgr_a%30Sd", chat_affiliate_program("username", "a0Sd"));

  parse_internal_link("tg:resolve?domain=username&direct=aasdasd", direct_messages_chat("username"));
  parse_internal_link("TG://resolve?domain=username&direct=", direct_messages_chat("username"));
  parse_internal_link("TG://test@resolve?domain=username&direct=", nullptr);
  parse_internal_link("tg:resolve:80?domain=username&direct=", nullptr);
  parse_internal_link("tg:http://resolve?domain=username&direct=", nullptr);
  parse_internal_link("tg:https://resolve?domain=username&direct=", nullptr);
  parse_internal_link("tg:resolve?domain=&direct=", unknown_deep_link("tg://resolve?domain=&direct="));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&direct=%30", direct_messages_chat("telegram"));

  parse_internal_link("t.me/username/0/a//s/as?direct=", direct_messages_chat("username"));
  parse_internal_link("t.me/username/aasdas/2?test=1&direct=#12312", direct_messages_chat("username"));
  parse_internal_link("t.me/username/0?direct=", direct_messages_chat("username"));
  parse_internal_link("t.me/username/-1?direct=asdasd", direct_messages_chat("username"));
  parse_internal_link("t.me/username?direct=", direct_messages_chat("username"));
  parse_internal_link("t.me/username#direct=asdas", public_chat("username"));
  parse_internal_link("t.me//username?direct=", nullptr);
  parse_internal_link("https://telegram.dog/tele%63ram?direct=t%63st", direct_messages_chat("telecram"));

  parse_internal_link("tg:resolve?domain=username&direct=_tgr_", direct_messages_chat("username"));
  parse_internal_link("tg:resolve?domain=username&direct=_tgr_aSd", direct_messages_chat("username"));
  parse_internal_link("tg:resolve?domain=username&direct=_tgr_a%30Sd", direct_messages_chat("username"));

  parse_internal_link("t.me/username/0/a//s/as?direct=_tgr_", direct_messages_chat("username"));
  parse_internal_link("t.me/username/0/a//s/as?direct=_tgr_aSd", direct_messages_chat("username"));
  parse_internal_link("t.me/username/0/a//s/as?direct=_tgr_a%30Sd", direct_messages_chat("username"));

  parse_internal_link("tg:resolve?domain=username&ref=", public_chat("username"));
  parse_internal_link("tg:resolve?domain=username&ref=aSd", chat_affiliate_program("username", "aSd"));
  parse_internal_link("tg:resolve?domain=username&ref=a%30Sd", chat_affiliate_program("username", "a0Sd"));

  parse_internal_link("t.me/username/0/a//s/as?ref=", public_chat("username"));
  parse_internal_link("t.me/username/0/a//s/as?ref=aSd", chat_affiliate_program("username", "aSd"));
  parse_internal_link("t.me/username/0/a//s/as?ref=a%30Sd", chat_affiliate_program("username", "a0Sd"));

  parse_internal_link("tg:resolve?domain=username&startgroup=aasdasd",
                      bot_start_in_group("username", "aasdasd", nullptr));
  parse_internal_link("TG://resolve?domain=username&startgroup=", bot_start_in_group("username", "", nullptr));
  parse_internal_link("TG://test@resolve?domain=username&startgroup=", nullptr);
  parse_internal_link("tg:resolve:80?domain=username&startgroup=", nullptr);
  parse_internal_link("tg:http://resolve?domain=username&startgroup=", nullptr);
  parse_internal_link("tg:https://resolve?domain=username&startgroup=", nullptr);
  parse_internal_link("tg:resolve?domain=&startgroup=", unknown_deep_link("tg://resolve?domain=&startgroup="));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&startgroup=%30", bot_start_in_group("telegram", "0", nullptr));

  parse_internal_link("tg:resolve?domain=username&startgroup", bot_start_in_group("username", "", nullptr));
  parse_internal_link("tg:resolve?domain=username&startgroup&admin=asdas", bot_start_in_group("username", "", nullptr));
  parse_internal_link("tg:resolve?domain=username&startgroup&admin=post_messages",
                      bot_start_in_group("username", "", nullptr));
  parse_internal_link(
      "tg:resolve?domain=username&startgroup=1&admin=delete_messages+anonymous",
      bot_start_in_group("username", "1",
                         chat_administrator_rights(true, false, false, false, true, false, false, false, false, false,
                                                   false, false, false, false, false, false, true)));
  parse_internal_link(
      "tg:resolve?domain=username&startgroup&admin=manage_chat+change_info+post_messages+edit_messages+delete_messages+"
      "invite_users+restrict_members+pin_messages+manage_topics+promote_members+manage_video_chats+post_stories+edit_"
      "stories+delete_stories+anonymous+manage_direct_messages+manage_tags",
      bot_start_in_group("username", "",
                         chat_administrator_rights(true, true, false, false, true, true, true, true, true, true, true,
                                                   true, true, true, false, true, true)));

  parse_internal_link("tg:resolve?domain=username&startchannel", public_chat("username"));
  parse_internal_link("tg:resolve?domain=username&startchannel&admin=", public_chat("username"));
  parse_internal_link("tg:resolve?domain=username&startchannel&admin=post_messages+manage_direct_messages",
                      bot_add_to_channel("username", chat_administrator_rights(true, false, true, false, false, false,
                                                                               false, false, false, false, false, false,
                                                                               false, false, true, false, false)));
  parse_internal_link(
      "tg:resolve?domain=username&startchannel&admin=post_messages+manage_direct_messages+restrict_members",
      bot_add_to_channel("username",
                         chat_administrator_rights(true, false, true, false, false, false, true, false, false, false,
                                                   false, false, false, false, true, false, false)));
  parse_internal_link(
      "tg:resolve?domain=username&startchannel&admin=manage_chat+change_info+post_messages+edit_messages+delete_"
      "messages+invite_users+restrict_members+pin_messages+manage_topics+promote_members+manage_video_chats+anonymous+"
      "manage_direct_messages+manage_tags",
      bot_add_to_channel("username", chat_administrator_rights(true, true, true, true, true, true, true, false, false,
                                                               true, true, false, false, false, true, false, false)));

  parse_internal_link("t.me/username/0/a//s/as?startgroup=", bot_start_in_group("username", "", nullptr));
  parse_internal_link("t.me/username/aasdas/2?test=1&startgroup=#12312", bot_start_in_group("username", "", nullptr));
  parse_internal_link("t.me/username/0?startgroup=", bot_start_in_group("username", "", nullptr));
  parse_internal_link("t.me/username/-1?startgroup=asdasd", bot_start_in_group("username", "asdasd", nullptr));
  parse_internal_link("t.me/username?startgroup=", bot_start_in_group("username", "", nullptr));
  parse_internal_link("t.me/username#startgroup=asdas", public_chat("username"));
  parse_internal_link("t.me//username?startgroup=", nullptr);
  parse_internal_link("https://telegram.dog/tele%63ram?startgroup=t%63st",
                      bot_start_in_group("telecram", "tcst", nullptr));

  parse_internal_link("t.me/username?startgroup", bot_start_in_group("username", "", nullptr));
  parse_internal_link("t.me/username?startgroup&admin=asdas", bot_start_in_group("username", "", nullptr));
  parse_internal_link("t.me/username?startgroup&admin=post_messages", bot_start_in_group("username", "", nullptr));
  parse_internal_link(
      "t.me/username?startgroup=1&admin=delete_messages+anonymous",
      bot_start_in_group("username", "1",
                         chat_administrator_rights(true, false, false, false, true, false, false, false, false, false,
                                                   false, false, false, false, false, false, true)));
  parse_internal_link(
      "t.me/"
      "username?startgroup&admin=manage_chat+change_info+post_messages+edit_messages+delete_messages+invite_users+"
      "restrict_members+pin_messages+manage_topics+promote_members+manage_video_chats+post_stories+edit_stories+delete_"
      "stories+anonymous+manage_direct_messages+manage_tags",
      bot_start_in_group("username", "",
                         chat_administrator_rights(true, true, false, false, true, true, true, true, true, true, true,
                                                   true, true, true, false, true, true)));

  parse_internal_link("t.me/username?startchannel", public_chat("username"));
  parse_internal_link("t.me/username?startchannel&admin=", public_chat("username"));
  parse_internal_link("t.me/username?startchannel&admin=post_messages",
                      bot_add_to_channel("username", chat_administrator_rights(true, false, true, false, false, false,
                                                                               false, false, false, false, false, false,
                                                                               false, false, false, false, false)));
  parse_internal_link(
      "t.me/"
      "username?startchannel&admin=manage_chat+change_info+post_messages+edit_messages+delete_messages+invite_users+"
      "restrict_members+pin_messages+manage_topics+promote_members+manage_video_chats+post_stories+edit_stories+delete_"
      "stories+anonymous+manage_direct_messages+manage_tags",
      bot_add_to_channel("username", chat_administrator_rights(true, true, true, true, true, true, true, false, false,
                                                               true, true, true, true, true, true, false, false)));
}

TEST(Link, parse_internal_link_part4) {
  parse_internal_link("tg:resolve?domain=username&game=aasdasd", game("username", "aasdasd"));
  parse_internal_link("TG://resolve?domain=username&game=", public_chat("username"));
  parse_internal_link("TG://test@resolve?domain=username&game=asd", nullptr);
  parse_internal_link("tg:resolve:80?domain=username&game=asd", nullptr);
  parse_internal_link("tg:http://resolve?domain=username&game=asd", nullptr);
  parse_internal_link("tg:https://resolve?domain=username&game=asd", nullptr);
  parse_internal_link("tg:resolve?domain=&game=asd", unknown_deep_link("tg://resolve?domain=&game=asd"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&game=%30", public_chat("telegram"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&game=%30ab", public_chat("telegram"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&game=ab%30", game("telegram", "ab0"));

  parse_internal_link("t.me/username/0/a//s/as?game=asd", game("username", "asd"));
  parse_internal_link("t.me/username/aasdas/2?test=1&game=asd#12312", game("username", "asd"));
  parse_internal_link("t.me/username/0?game=asd", game("username", "asd"));
  parse_internal_link("t.me/username/-1?game=asdasd", game("username", "asdasd"));
  parse_internal_link("t.me/username?game=asd", game("username", "asd"));
  parse_internal_link("t.me/username?game=", public_chat("username"));
  parse_internal_link("t.me/username#game=asdas", public_chat("username"));
  parse_internal_link("t.me//username?game=asd", nullptr);
  parse_internal_link("https://telegram.dog/tele%63ram?game=t%63st", game("telecram", "tcst"));

  parse_internal_link("tg:resolve?domain=username&collection=123", gift_collection("username", 123));
  parse_internal_link("TG://resolve?domain=username&collection=", public_chat("username"));
  parse_internal_link("TG://resolve?domain=username&collection=0", public_chat("username"));
  parse_internal_link("TG://resolve?domain=username&collection=-1", public_chat("username"));
  parse_internal_link("TG://test@resolve?domain=username&collection=1", nullptr);
  parse_internal_link("tg:resolve:80?domain=username&collection=1", nullptr);
  parse_internal_link("tg:http://resolve?domain=username&collection=1", nullptr);
  parse_internal_link("tg:https://resolve?domain=username&collection=1", nullptr);
  parse_internal_link("tg:resolve?domain=&collection=1", unknown_deep_link("tg://resolve?domain=&collection=1"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&collection=%30", public_chat("telegram"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&collection=%31", gift_collection("telegram", 1));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&collection=%31ab", public_chat("telegram"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&collection=%31%39", gift_collection("telegram", 19));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&collection=2222222222", public_chat("telegram"));

  parse_internal_link("t.me/username/c/1234", gift_collection("username", 1234));
  parse_internal_link("t.me/username/c/3?qwe=12312#12312", gift_collection("username", 3));
  parse_internal_link("t.me/username/c/1", gift_collection("username", 1));
  parse_internal_link("t.me/username/c/2", gift_collection("username", 2));
  parse_internal_link("t.me/username/c/5", gift_collection("username", 5));
  parse_internal_link("t.me/username/c/", public_chat("username"));
  parse_internal_link("t.me/username#/c/123", public_chat("username"));
  parse_internal_link("t.me/username?gift_collection=123&collection=123", public_chat("username"));
  parse_internal_link("https://telegram.dog/tele%63ram/c/%31%39", gift_collection("telecram", 19));

  parse_internal_link("tg:resolve?domain=username&story=123", story("username", 123));
  parse_internal_link("TG://resolve?domain=username&story=", public_chat("username"));
  parse_internal_link("TG://resolve?domain=username&story=0", public_chat("username"));
  parse_internal_link("TG://resolve?domain=username&story=-1", public_chat("username"));
  parse_internal_link("TG://test@resolve?domain=username&story=1", nullptr);
  parse_internal_link("tg:resolve:80?domain=username&story=1", nullptr);
  parse_internal_link("tg:http://resolve?domain=username&story=1", nullptr);
  parse_internal_link("tg:https://resolve?domain=username&story=1", nullptr);
  parse_internal_link("tg:resolve?domain=&story=1", unknown_deep_link("tg://resolve?domain=&story=1"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&story=%30", public_chat("telegram"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&story=%31", story("telegram", 1));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&story=%31ab", public_chat("telegram"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&story=%31%39", story("telegram", 19));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&story=2222222222", public_chat("telegram"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&story=live", live_story("telegram"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&story=Live", public_chat("telegram"));

  parse_internal_link("t.me/username/s/1234", story("username", 1234));
  parse_internal_link("t.me/username/s/3?qwe=12312#12312", story("username", 3));
  parse_internal_link("t.me/username/s/1", story("username", 1));
  parse_internal_link("t.me/username/s/2", story("username", 2));
  parse_internal_link("t.me/username/s/5", story("username", 5));
  parse_internal_link("t.me/username/s/live", live_story("username"));
  parse_internal_link("t.me/username/s/Live", public_chat("username"));
  parse_internal_link("t.me/username/s/", public_chat("username"));
  parse_internal_link("t.me/username#/s/123", public_chat("username"));
  parse_internal_link("t.me/username?story=123", public_chat("username"));
  parse_internal_link("https://telegram.dog/tele%63ram/s/%31%39", story("telecram", 19));

  parse_internal_link("tg:resolve?domain=username&album=123", story_album("username", 123));
  parse_internal_link("TG://resolve?domain=username&album=", public_chat("username"));
  parse_internal_link("TG://resolve?domain=username&album=0", public_chat("username"));
  parse_internal_link("TG://resolve?domain=username&album=-1", public_chat("username"));
  parse_internal_link("TG://test@resolve?domain=username&album=1", nullptr);
  parse_internal_link("tg:resolve:80?domain=username&album=1", nullptr);
  parse_internal_link("tg:http://resolve?domain=username&album=1", nullptr);
  parse_internal_link("tg:https://resolve?domain=username&album=1", nullptr);
  parse_internal_link("tg:resolve?domain=&album=1", unknown_deep_link("tg://resolve?domain=&album=1"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&album=%30", public_chat("telegram"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&album=%31", story_album("telegram", 1));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&album=%31ab", public_chat("telegram"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&album=%31%39", story_album("telegram", 19));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&album=2222222222", public_chat("telegram"));

  parse_internal_link("t.me/username/a/1234", story_album("username", 1234));
  parse_internal_link("t.me/username/a/3?qwe=12312#12312", story_album("username", 3));
  parse_internal_link("t.me/username/a/1", story_album("username", 1));
  parse_internal_link("t.me/username/a/2", story_album("username", 2));
  parse_internal_link("t.me/username/a/5", story_album("username", 5));
  parse_internal_link("t.me/username/a/", public_chat("username"));
  parse_internal_link("t.me/username#/a/123", public_chat("username"));
  parse_internal_link("t.me/username?story_album=123&album=123", public_chat("username"));
  parse_internal_link("https://telegram.dog/tele%63ram/a/%31%39", story_album("telecram", 19));

  parse_internal_link("t.me/h", public_chat("h"));
  parse_internal_link("t.me/h/hh", public_chat("h"));
  parse_internal_link("t.me/i", nullptr);
  parse_internal_link("t.me/i/ii", nullptr);
  parse_internal_link("t.me/j", public_chat("j"));
  parse_internal_link("t.me/j/jj", public_chat("j"));

  parse_internal_link("tg:resolve?domain=username&appname=aasdasd&startapp=123asd",
                      web_app("username", "aasdasd", "123asd", false, false));
  parse_internal_link("TG://resolve?domain=username&appname=&startapp=123asd", public_chat("username"));
  parse_internal_link("TG://test@resolve?domain=username&appname=asd", nullptr);
  parse_internal_link("tg:resolve:80?domain=username&appname=asd", nullptr);
  parse_internal_link("tg:http://resolve?domain=username&appname=asd", nullptr);
  parse_internal_link("tg:https://resolve?domain=username&appname=asd", nullptr);
  parse_internal_link("tg:resolve?domain=&appname=asd", unknown_deep_link("tg://resolve?domain=&appname=asd"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&appname=%41&startapp=", public_chat("telegram"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&appname=%41b&startapp=", public_chat("telegram"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&appname=%41bc&startapp=",
                      web_app("telegram", "Abc", "", false, false));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&appname=%41bc&startapp=&mode=compact",
                      web_app("telegram", "Abc", "", true, false));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&appname=%41bc&startapp=&mode=fullscreen",
                      web_app("telegram", "Abc", "", false, true));

  parse_internal_link("t.me/username/0/a//s/as?appname=asd", public_chat("username"));
  parse_internal_link("t.me/username/aasdas/2?test=1&appname=asd#12312", public_chat("username"));
  parse_internal_link("t.me/username/0?appname=asd", public_chat("username"));
  parse_internal_link("t.me/username/-1?appname=asdasd", public_chat("username"));
  parse_internal_link("t.me/username?appname=asd", public_chat("username"));
  parse_internal_link("t.me/username?appname=", public_chat("username"));
  parse_internal_link("t.me/username#appname=asdas", public_chat("username"));
  parse_internal_link("t.me//username?appname=asd", nullptr);
  parse_internal_link("https://telegram.dog/tele%63ram?appname=t%63st", public_chat("telecram"));
  parse_internal_link("t.me/username/def/asd", public_chat("username"));
  parse_internal_link("t.me/username/asd#12312&startapp=qwe", web_app("username", "asd", "", false, false));
  parse_internal_link("t.me/username/asd?12312&startapp=qwe&mode=compac",
                      web_app("username", "asd", "qwe", false, false));
  parse_internal_link("t.me/username/asd?12312&startapp=qwe&mode=compact",
                      web_app("username", "asd", "qwe", true, false));
  parse_internal_link("t.me/username/asd?12312&startapp=qwe&mode=fullscreen",
                      web_app("username", "asd", "qwe", false, true));
  parse_internal_link("t.me/username/asdasd?startapp=0", web_app("username", "asdasd", "0", false, false));
  parse_internal_link("t.me/username/asd", web_app("username", "asd", "", false, false));
  parse_internal_link("t.me/username/", public_chat("username"));
  parse_internal_link("https://telegram.dog/tele%63ram/t%63st", web_app("telecram", "tcst", "", false, false));
  parse_internal_link("https://telegram.dog/tele%63ram/t%63st?mode=compact",
                      web_app("telecram", "tcst", "", true, false));
  parse_internal_link("https://telegram.dog/tele%63ram/t%63st?mode=fullscreen",
                      web_app("telecram", "tcst", "", false, true));

  parse_internal_link("tg:resolve?domain=username&startapp=aasdasd", main_web_app("username", "aasdasd", false, false));
  parse_internal_link("TG://resolve?domain=username&startapp=&startapp=123asd",
                      main_web_app("username", "", false, false));
  parse_internal_link("TG://test@resolve?domain=username&startapp=asd", nullptr);
  parse_internal_link("tg:resolve:80?domain=username&startapp=asd", nullptr);
  parse_internal_link("tg:http://resolve?domain=username&startapp=asd", nullptr);
  parse_internal_link("tg:https://resolve?domain=username&startapp=asd", nullptr);
  parse_internal_link("tg:resolve?domain=&startapp=asd", unknown_deep_link("tg://resolve?domain=&startapp=asd"));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&startapp=%41", main_web_app("telegram", "A", false, false));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&startapp=%41b", main_web_app("telegram", "Ab", false, false));
  parse_internal_link("tg:resolve?domain=telegram&&&&&&&startapp=%41bc", main_web_app("telegram", "Abc", false, false));
  parse_internal_link("tg:resolve?domain=telegram&&mode=compact&&&&&&startapp=%41bc",
                      main_web_app("telegram", "Abc", true, false));
  parse_internal_link("tg:resolve?domain=telegram&&mode=fullscreen&&&&&&startapp=%41bc",
                      main_web_app("telegram", "Abc", false, true));
  parse_internal_link("tg:resolve?domain=username&startapp=*", public_chat("username"));
  parse_internal_link("tg:resolve?domain=username&startapp=%30", main_web_app("username", "0", false, false));

  parse_internal_link("t.me/username?startapp=qwe", main_web_app("username", "qwe", false, false));
  parse_internal_link("t.me/username?12312&startapp=qwe", main_web_app("username", "qwe", false, false));
  parse_internal_link("t.me/username?startapp=0", main_web_app("username", "0", false, false));
  parse_internal_link("https://telegram.dog/tele%63ram?startapp=t%63st",
                      main_web_app("telecram", "tcst", false, false));
  parse_internal_link("https://telegram.dog/tele%63ram?startapp=t%63st&mode=%63ompact",
                      main_web_app("telecram", "tcst", true, false));
  parse_internal_link("https://telegram.dog/tele%63ram?startapp=t%63st&mode=%66ullscreen",
                      main_web_app("telecram", "tcst", false, true));
  parse_internal_link("https://telegram.dog?startapp=t%63st", nullptr);
  parse_internal_link("t.me/username?startapp=%30", main_web_app("username", "0", false, false));
  parse_internal_link("t.me/username?startapp=*", public_chat("username"));

  parse_internal_link("tg:resolve?domain=username&Game=asd", public_chat("username"));
  parse_internal_link("TG://test@resolve?domain=username", nullptr);
  parse_internal_link("tg:resolve:80?domain=username", nullptr);
  parse_internal_link("tg:http://resolve?domain=username", nullptr);
  parse_internal_link("tg:https://resolve?domain=username", nullptr);
  parse_internal_link("tg:resolve?domain=", unknown_deep_link("tg://resolve?domain="));
  parse_internal_link("tg:resolve?&&&&&&&domain=telegram", public_chat("telegram"));

  parse_internal_link("t.me/a", public_chat("a"));
  parse_internal_link("t.me/abcdefghijklmnopqrstuvwxyz123456", public_chat("abcdefghijklmnopqrstuvwxyz123456"));
  parse_internal_link("t.me/abcdefghijklmnopqrstuvwxyz1234567", nullptr);
  parse_internal_link("t.me/abcdefghijklmnop-qrstuvwxyz", nullptr);
  parse_internal_link("t.me/abcdefghijklmnop~qrstuvwxyz", nullptr);
  parse_internal_link("t.me/_asdf", nullptr);
  parse_internal_link("t.me/0asdf", nullptr);
  parse_internal_link("t.me/9asdf", nullptr);
  parse_internal_link("t.me/Aasdf", public_chat("Aasdf"));
  parse_internal_link("t.me/asdf_", nullptr);
  parse_internal_link("t.me/asdf0", public_chat("asdf0"));
  parse_internal_link("t.me/asd__fg", nullptr);
  parse_internal_link("t.me/username/0/a//s/as?gam=asd", public_chat("username"));
  parse_internal_link("t.me/username/aasdas/2?test=1", public_chat("username"));
  parse_internal_link("t.me/username/0", public_chat("username"));
  parse_internal_link("t.me//username", nullptr);
  parse_internal_link("https://telegram.dog/tele%63ram", public_chat("telecram"));

  parse_internal_link(
      "tg://"
      "resolve?domain=telegrampassport&bot_id=543260180&scope=%7B%22v%22%3A1%2C%22d%22%3A%5B%7B%22%22%5D%7D%5D%7D&"
      "public_key=BEGIN%20PUBLIC%20KEY%0A&nonce=b8ee&callback_url=https%3A%2F%2Fcore.telegram.org%2Fpassport%2Fexample%"
      "3Fpassport_ssid%3Db8ee&payload=nonce",
      passport_data_request(543260180, "{\"v\":1,\"d\":[{\"\"]}]}", "BEGIN PUBLIC KEY\n", "b8ee",
                            "https://core.telegram.org/passport/example?passport_ssid=b8ee"));
  parse_internal_link("tg://resolve?domain=telegrampassport&bot_id=12345&public_key=key&scope=asd&payload=nonce",
                      passport_data_request(12345, "asd", "key", "nonce", ""));
  parse_internal_link("tg://passport?bot_id=12345&public_key=key&scope=asd&payload=nonce",
                      passport_data_request(12345, "asd", "key", "nonce", ""));
  parse_internal_link("tg://passport?bot_id=0&public_key=key&scope=asd&payload=nonce",
                      unknown_deep_link("tg://passport?bot_id=0&public_key=key&scope=asd&payload=nonce"));
  parse_internal_link("tg://passport?bot_id=-1&public_key=key&scope=asd&payload=nonce",
                      unknown_deep_link("tg://passport?bot_id=-1&public_key=key&scope=asd&payload=nonce"));
  parse_internal_link("tg://passport?bot_id=12345&public_key=&scope=asd&payload=nonce",
                      unknown_deep_link("tg://passport?bot_id=12345&public_key=&scope=asd&payload=nonce"));
  parse_internal_link("tg://passport?bot_id=12345&public_key=key&scope=&payload=nonce",
                      unknown_deep_link("tg://passport?bot_id=12345&public_key=key&scope=&payload=nonce"));
  parse_internal_link("tg://passport?bot_id=12345&public_key=key&scope=asd&payload=",
                      unknown_deep_link("tg://passport?bot_id=12345&public_key=key&scope=asd&payload="));
  parse_internal_link("tg://passport?bot_id=12345&public_key=key%FF&scope=asd&payload=nonce",
                      unknown_deep_link("tg://passport?bot_id=12345&public_key=key%FF&scope=asd&payload=nonce"));
  parse_internal_link("tg://passport?bot_id=12345&public_key=key&scope=asd%FF&payload=nonce",
                      unknown_deep_link("tg://passport?bot_id=12345&public_key=key&scope=asd%FF&payload=nonce"));
  parse_internal_link("tg://passport?bot_id=12345&public_key=key&scope=asd&payload=nonce%FF",
                      unknown_deep_link("tg://passport?bot_id=12345&public_key=key&scope=asd&payload=nonce%FF"));

  parse_internal_link("t.me/telegrampassport?bot_id=12345&public_key=key&scope=asd&payload=nonce",
                      public_chat("telegrampassport"));
  parse_internal_link("t.me/telegrampassport?bot_id=12345&public_key=key%FF&scope=asd&payload=nonce",
                      public_chat("telegrampassport"));
  parse_internal_link("t.me/telegrampassport?bot_id=12345&public_key=key&scope=asd%FF&payload=nonce",
                      public_chat("telegrampassport"));
  parse_internal_link("t.me/telegrampassport?bot_id=12345&public_key=key&scope=asd&payload=nonce%FF",
                      public_chat("telegrampassport"));

  parse_internal_link("tg:premium_offer?ref=abcdef", premium_features_page("abcdef"));
  parse_internal_link("tg:premium_offer?ref=abc%30ef", premium_features_page("abc0ef"));
  parse_internal_link("tg:premium_offer?ref=abcde%ff", unknown_deep_link("tg://premium_offer?ref=abcde%ff"));
  parse_internal_link("tg://premium_offer?ref=", premium_features_page(""));

  parse_internal_link("tg:premium_multigift?ref=abcdef", premium_gift_purchase("abcdef"));
  parse_internal_link("tg:premium_multigift?ref=abc%30ef", premium_gift_purchase("abc0ef"));
  parse_internal_link("tg:premium_multigift?ref=abcde%ff", unknown_deep_link("tg://premium_multigift?ref=abcde%ff"));
  parse_internal_link("tg://premium_multigift?ref=", premium_gift_purchase(""));

  parse_internal_link("t.me/newbot/0manager/tesager?name=", public_chat("newbot"));
  parse_internal_link("t.me/newbot/manager/0testbot?name=", public_chat("newbot"));
  parse_internal_link("t.me/newbot/manager", request_managed_bot("manager", "bot", ""));
  parse_internal_link("t.me/newbot/manager?name=asd", request_managed_bot("manager", "bot", "asd"));
  parse_internal_link("t.me/newbot/manager/a?name=asd", request_managed_bot("manager", "abot", "asd"));
  parse_internal_link("t.me/newbot/manager/testbot?name=", request_managed_bot("manager", "testbot", ""));
  parse_internal_link("t.me/newbot/manager/testbot?name=asd", request_managed_bot("manager", "testbot", "asd"));
  parse_internal_link("t.me/newbot/manager/testBot?name=asd", request_managed_bot("manager", "testBot", "asd"));
  parse_internal_link("t.me/newbot/manager/testbOt?name=asd", request_managed_bot("manager", "testbOt", "asd"));

  parse_internal_link("tg:newbot?manager=managerot&username=testbot&name=asd",
                      request_managed_bot("managerot", "testbot", "asd"));
  parse_internal_link("tg:newbot?manager=managerot&username=testbot", request_managed_bot("managerot", "testbot", ""));
  parse_internal_link("tg:newbot?manager=0manager&username=testbot",
                      unknown_deep_link("tg://newbot?manager=0manager&username=testbot"));
  parse_internal_link("tg:newbot?manager=managerot&username=0testbot",
                      unknown_deep_link("tg://newbot?manager=managerot&username=0testbot"));

  parse_internal_link("tg://settings", settings());
  parse_internal_link("tg://setting", unknown_deep_link("tg://setting"));
  parse_internal_link("tg://settings?asdsa?D?SADasD?asD", settings());
  parse_internal_link("tg://settings#test", settings());
  parse_internal_link("tg://settings/#test", settings());
  parse_internal_link("tg://settings/aadsa#test", settings());
  parse_internal_link("tg://settings/theme#test", settings());
  parse_internal_link("tg://settings/themes#test", appearance());
  parse_internal_link("tg://settings/appearance#test", appearance());
  parse_internal_link("tg://settings/themesa#test", settings());
  parse_internal_link("tg://settings/themes/?as#rad", appearance());
  parse_internal_link("tg://settings/appearance/?as#rad", appearance());
  parse_internal_link("tg://settings/themes/a", appearance());
  parse_internal_link("tg://settings/appearance/a", appearance());
  parse_internal_link("tg://settings/asdsathemesasdas/devices", settings());
  parse_internal_link("tg://settings/auto_delete", privacy_and_security_settings("auto-delete"));
  parse_internal_link("tg://settings/auto_delete/test", privacy_and_security_settings("auto-delete"));
  parse_internal_link("tg://settings/devices", devices());
  parse_internal_link("tg://settings/change_number", edit_profile_settings("change-number"));
  parse_internal_link("tg://settings/data", data_and_storage_settings());
  parse_internal_link("tg://settings/edit_profile", edit_profile_settings());
  parse_internal_link("tg://settings/edit", edit_profile_settings());
  parse_internal_link("tg://settings/folders", chat_folder_settings());
  parse_internal_link("tg://settings/filters", settings());
  parse_internal_link("tg://settings/language", language_settings());
  parse_internal_link("tg://settings/login_email", privacy_and_security_settings("login-email"));
  parse_internal_link("tg://settings/notifications", notification_settings());
  parse_internal_link("tg://settings/password", privacy_and_security_settings("2sv"));
  parse_internal_link("tg://settings/phone_privacy", privacy_and_security_settings("phone-number"));
  parse_internal_link("tg://settings/power-saving", power_saving());
  parse_internal_link("tg://settings/privacy", privacy_and_security_settings());

  parse_internal_link("tg://settings/language/abacaba", language_settings());
  parse_internal_link("tg://settings/language/show-button", language_settings("show-button"));
  parse_internal_link("tg://settings/language/translate-chats", language_settings("translate-chats"));
  parse_internal_link("tg://settings/language/do-not-translate", language_settings("do-not-translate"));

  parse_internal_link("tg://settings/privacy/abacaba", privacy_and_security_settings());
  parse_internal_link("tg://settings/privacy/auto-delete", privacy_and_security_settings("auto-delete"));
  parse_internal_link("tg://settings/privacy/passcode/auto-lock", privacy_and_security_settings("passcode/auto-lock"));
  parse_internal_link("tg://settings/privacy/passcode/auto-locks", privacy_and_security_settings());
  parse_internal_link("tg://settings/privacy/phone-number/never", privacy_and_security_settings("phone-number/never"));
  parse_internal_link("tg://settings/privacy/phone-number/never-share", privacy_and_security_settings());
  parse_internal_link("tg://settings/privacy/login-email", privacy_and_security_settings("login-email"));
  parse_internal_link("tg://settings/privacy/phone-number", privacy_and_security_settings("phone-number"));
  parse_internal_link("tg://settings/privacy/auto-delete/set-custom",
                      privacy_and_security_settings("auto-delete/set-custom"));

  parse_internal_link("tg://settings/appearance/themes", appearance("themes"));
  parse_internal_link("tg://settings/appearance/themes/edit", appearance("themes/edit"));
  parse_internal_link("tg://settings/appearance/app-icon", appearance("app-icon"));

  parse_internal_link("tg://settings/devices/edit", devices("edit"));
  parse_internal_link("tg://settings/devices/auto-terminate", devices("auto-terminate"));

  parse_internal_link("tg://settings/folders/edit", chat_folder_settings("edit"));
  parse_internal_link("tg://settings/folders/tab-view", chat_folder_settings("tab-view"));

  parse_internal_link("tg://settings/edit/abacaba", edit_profile_settings());
  parse_internal_link("tg://settings/edit-profile/abacaba", settings());
  parse_internal_link("tg://settings/edit_profile/abacaba", edit_profile_settings());
  parse_internal_link("tg://settings/edit/log-out", edit_profile_settings("log-out"));
  parse_internal_link("tg://settings/edit_profile/log-out", edit_profile_settings());
  parse_internal_link("tg://settings/edit/your-color", edit_profile_settings("your-color"));
  parse_internal_link("tg://settings/edit_profile/your-color", edit_profile_settings());
  parse_internal_link("tg://settings/edit/change_number", edit_profile_settings());
  parse_internal_link("tg://settings/edit/change-number", edit_profile_settings("change-number"));
  parse_internal_link("tg://settings/emoji-status", edit_profile_settings("emoji-status"));
  parse_internal_link("tg://settings/profile-color", edit_profile_settings());
  parse_internal_link("tg://settings/profile-color/abacaba", edit_profile_settings());
  parse_internal_link("tg://settings/profile-color/profile", edit_profile_settings("profile-color/profile"));
  parse_internal_link("tg://settings/profile-color/profile/abacaba", edit_profile_settings());
  parse_internal_link("tg://settings/profile-color/profile/use-gift",
                      edit_profile_settings("profile-color/profile/use-gift"));
  parse_internal_link("tg://settings/profile-photo", edit_profile_settings());
  parse_internal_link("tg://settings/profile-photo/use-emojis", edit_profile_settings());
  parse_internal_link("tg://settings/profile-photo/use-emoji", edit_profile_settings("profile-photo/use-emoji"));

  parse_internal_link("tg://settings/notifications/app-icon", notification_settings());
  parse_internal_link("tg://settings/notifications/reset", notification_settings("reset"));
  parse_internal_link("tg://settings/notifications/groups/delete-exceptions",
                      notification_settings("groups/delete-exceptions"));

  parse_internal_link("tg://settings/power-saving/app-icon", power_saving());
  parse_internal_link("tg://settings/power-saving/call-animations", power_saving("call-animations"));
  parse_internal_link("tg://settings/power-saving/transitions", power_saving("transitions"));

  parse_internal_link("tg://settings/data/app-icon", data_and_storage_settings());
  parse_internal_link("tg://settings/data/reset", data_and_storage_settings());
  parse_internal_link("tg://settings/data/storage", data_and_storage_settings("storage"));
  parse_internal_link("tg://settings/data/proxy/use-for-calls", data_and_storage_settings("proxy/use-for-calls"));

  parse_internal_link("tg://stars", my_stars());
  parse_internal_link("tg://stars?asdsa?D?SADasD?asD", my_stars());
  parse_internal_link("tg://stars#test", my_stars());
  parse_internal_link("tg://stars/#test", my_stars());
  parse_internal_link("tg://stars/aadsa#test", my_stars());
  parse_internal_link("tg://stars/theme#test", my_stars());
  parse_internal_link("tg:stars/theme#test", my_stars());
  parse_internal_link("tg://stars/earn#test", my_stars());
  parse_internal_link("tg://settings/stars", my_stars());
  parse_internal_link("tg://settings/stars/123123", my_stars());
  parse_internal_link("tg://settings/stars/earn#test", my_stars("earn"));

  parse_internal_link("tg://ton", my_toncoins());
  parse_internal_link("tg://ton?asdsa?D?SADasD?asD", my_toncoins());
  parse_internal_link("tg://ton#test", my_toncoins());
  parse_internal_link("tg://ton/#test", my_toncoins());
  parse_internal_link("tg://ton/aadsa#test", my_toncoins());
  parse_internal_link("tg://ton/theme#test", my_toncoins());
  parse_internal_link("tg:ton/theme#test", my_toncoins());
  parse_internal_link("tg://settings/ton", my_toncoins());
  parse_internal_link("tg://settings/ton/12312", my_toncoins());

  parse_internal_link("tg://premium", unknown_deep_link("tg://premium"));
  parse_internal_link("tg://settings/premium", premium());

  parse_internal_link("tg://ask-question", unknown_deep_link("tg://ask-question"));
  parse_internal_link("tg://settings/ask-question", ask_question());

  parse_internal_link("tg://settings/business", business());
  parse_internal_link("tg://settings/business/share", business());
  parse_internal_link("tg://settings/business/do-not-hide-ads", business("do-not-hide-ads"));

  parse_internal_link("tg://faq", unknown_deep_link("tg://faq"));
  parse_internal_link("tg://settings/faq", faq());

  parse_internal_link("tg://features", unknown_deep_link("tg://features"));
  parse_internal_link("tg://settings/features", features());

  parse_internal_link("tg://privacy-policy", unknown_deep_link("tg://privacy-policy"));
  parse_internal_link("tg://settings/privacy-policy", privacy_policy());

  parse_internal_link("tg://search", unknown_deep_link("tg://search"));
  parse_internal_link("tg://settings/search", settings_search());

  parse_internal_link("tg://settings/chat/browser", in_app_browser());
  parse_internal_link("tg://settings/chat/browser/", in_app_browser());
  parse_internal_link("tg://settings/chat/browser/abaa", in_app_browser());
  parse_internal_link("tg://settings/chat/browser/history", in_app_browser("history"));
  parse_internal_link("tg://settings/chat/browser/search", in_app_browser("search"));

  parse_internal_link("tg://settings/qr-code", qr_code());
  parse_internal_link("tg://settings/qr-code/share", qr_code("share"));
  parse_internal_link("tg://settings/qr-code/share/", qr_code("share"));
  parse_internal_link("tg://settings/qr-code/share/a", qr_code());

  parse_internal_link("tg://settings/send-gift", send_gift());
  parse_internal_link("tg://settings/send-gift/self", send_gift("self"));
  parse_internal_link("tg://settings/send-gift/self/", send_gift("self"));
  parse_internal_link("tg://settings/send-gift/self/a", send_gift());

  parse_internal_link("tg://stars_topup", unknown_deep_link("tg://stars_topup"));
  parse_internal_link("tg://stars_topup?balance=", unknown_deep_link("tg://stars_topup?balance="));
  parse_internal_link("tg://stars_topup?balance=test", star_purchase(1, ""));
  parse_internal_link("tg://stars_topup?balance=10&purpose=%30test", star_purchase(10, "0test"));
  parse_internal_link("tg://stars_topup?balance=100000000000&purpose=subs", star_purchase(100000000000, "subs"));
  parse_internal_link("tg://stars_topup?balance=10&purpose=%FFtest",
                      unknown_deep_link("tg://stars_topup?balance=10&purpose=%FFtest"));

  parse_internal_link("username.t.me////0/a//s/as?start=", bot_start("username", ""));
  parse_internal_link("username.t.me?start=as", bot_start("username", "as"));
  parse_internal_link("username.t.me", public_chat("username"));
  parse_internal_link("aAAb.t.me/12345?single", message("tg://resolve?domain=aaab&post=12345&single"));
  parse_internal_link("telegram.t.me/195", message("tg://resolve?domain=telegram&post=195"));
  parse_internal_link("shares.t.me", public_chat("shares"));

  parse_internal_link("c.t.me/12345?single", nullptr);
  parse_internal_link("aaa.t.me/12345?single", nullptr);
  parse_internal_link("aaa_.t.me/12345?single", nullptr);
  parse_internal_link("0aaa.t.me/12345?single", nullptr);
  parse_internal_link("_aaa.t.me/12345?single", nullptr);
  parse_internal_link("a.t.me", nullptr);
  parse_internal_link("b.t.me", nullptr);
  parse_internal_link("k.t.me", nullptr);
  parse_internal_link("z.t.me", nullptr);
  parse_internal_link("web.t.me", nullptr);
  parse_internal_link("addemoji.t.me", nullptr);
  parse_internal_link("addlist.t.me", nullptr);
  parse_internal_link("addstickers.t.me", nullptr);
  parse_internal_link("addstyle.t.me", nullptr);
  parse_internal_link("addtheme.t.me", nullptr);
  parse_internal_link("auction.t.me", nullptr);
  parse_internal_link("auth.t.me", nullptr);
  parse_internal_link("boost.t.me", nullptr);
  parse_internal_link("call.t.me", nullptr);
  parse_internal_link("confirmphone.t.me", nullptr);
  parse_internal_link("contact.t.me", nullptr);
  parse_internal_link("giftcode.t.me", nullptr);
  parse_internal_link("invoice.t.me", nullptr);
  parse_internal_link("joinchat.t.me", nullptr);
  parse_internal_link("login.t.me", nullptr);
  parse_internal_link("m.t.me", nullptr);
  parse_internal_link("nft.t.me", nullptr);
  parse_internal_link("proxy.t.me", nullptr);
  parse_internal_link("setlanguage.t.me", nullptr);
  parse_internal_link("share.t.me", nullptr);
  parse_internal_link("socks.t.me", nullptr);

  parse_internal_link("www.telegra.ph/", nullptr);
  parse_internal_link("www.telegrA.ph/#", nullptr);
  parse_internal_link("www.telegrA.ph/?", instant_view("https://telegra.ph/?", "www.telegrA.ph/?"));
  parse_internal_link("http://te.leGra.ph/?", instant_view("https://telegra.ph/?", "http://te.leGra.ph/?"));
  parse_internal_link("https://grAph.org/12345", instant_view("https://telegra.ph/12345", "https://grAph.org/12345"));
}
