var RNUtil = (function () {

	// Regexes
	var itemRe = /^\/item\/?$/;
	var itemSEORe = /^\/[^/]+-i\.(\d+)\.(\d+)\/?$/;
	var itemPCUrlRe = /^\/product\/(\d+)\/(\d+)\/?$/;
	var shopRe = /^\/shop\/?$/;
	var categorySEORe = /^\/[^/]+-cat\.(\d+)\/?$/;
	var subCategorySEORe = /^\/[^/]+-cat\.(\d+)\.(\d+)\/?$/;
	var subSubCategorySEORe = /^\/([^/]+)-cat\.(\d+)\.(\d+)\.(\d+)\/?$/;
	var categoryRe = /^\/categories\/(\d+)\/?$/;
	var categoryItemRe = /^\/category-item\/?$/;
	var searchRe = /^\/search-item\/?$/;
	var flashSaleUrlRe = /^\/(?:flash_?(?:deal|sale)s?|shocking_sale)\/$/;
	var collectionSEORe = /^\/[^/]+-col\.(\d+)\/?$/;
	var popularProductRe = /^\/popular_products\/?$/;
	var dailyDiscoverRe = /^\/daily_discover\/?$/;
	var justForYouRe = /\/recommend\/?$/;
	var campaignsRe = /^\/campaigns\/?$/;
	var bundleDealRe = /^\/bundle-deal\/(\d+)\/?$/;
	var referralRe = /^\/referral\/?$/;
	var buyerWalletRe = /^\/buyer\/myaccount\/wallet\/?$/;
	var shopSettingsRe = /^\/shop\/settings\/?$/;
	var groupBuyLandingPageGroupTabRe = /^\/group-and-save\/group\/?$/;
	var groupBuyLandingPageDealTabRe = /^\/group-and-save\/deal\/?$/;
	var groupInviteRe = /^\/group-buy-invite\/(\d+)\/?$/;
	var similarProductsRe = /^\/find_similar_products\/?$/;
	var officialShopRe = /^\/mall\/?$/;
	var officialShopSEORe = /^\/mall\/[^/]+-cat\.(\d+)\/?$/;
	var voucherInviteRe = /^\/voucher-wallet-invite\/(\d+)-(\w+)\/?$/;
	var voucherWalletUniversalLinkRe = /^\/universal-link\/user\/voucher-wallet\/?$/;
	var voucherWalletRe = /^\/user\/voucher-wallet\/?$/;
	var micrositeRe = /^\/m\//; // There will be other path after the /m/
	var slashPriceLandingPageRe = /^\/slash-price-lp\/?$/;
	var walletsiteRe = /^\/wallet\//;
	var bankAccountsRe = /^\/bank-accounts/;
	var mallFlashSaleRe = /^\/mall-flash-sale\/?$/;
	var otpVerifyRe = /^\/otp\/verify/;
	var coinsRewardPageRe = /^\/(shopee-coins|koin-shopee)\/?$/;

	/*  general config for urls navigates to RN TRANSFER_PAGE
	 *  `minRnVersion` indicates the minimal rn version supports navigation, null or undefined are the same as value=0
	 *  `transferPageRes` is re expression array of urls
	 */
	var transferPageConfigs = [
		{
			"minRnVersion": 1543991272,
			"featureName": "ratingFeature",
			"transferPageRes": [
				/^\/shop\/(\d+)\/rating\/?$/,
				/^\/buyer\/(\d+)\/rating\/?$/,
				/^\/shop\/(\d+)\/item\/(\d+)\/rating\/?$/,
			]
		}, {
			"minRnVersion": 1586026842,
			"featureName": "orderRatingFeature",
			"transferPageRes": [
				/^\/order\/buyer\/rate_order\/(\d+)\/?$/,
				/^\/order\/seller\/rate_order\/(\d+)\/?$/,
				/^\/shop\/rating\/buyer\/(\d+)\/?$/,
				/^\/shop\/rating\/seller\/(\d+)\/?$/,
			]
		}, {
			"featureName": "topProducts",
			"transferPageRes": [
				/^\/top_products\/?$/,
				/^\/top_products\/[^/]+-cat\.(\d+)\/?$/
			]
		}, {
			"featureName": "order_paid",
			"transferPageRes": [
				/^\/buyer\/order_paid\//
			]
		}
	];

	// Get page information and params for RN according to url
	function getRNParamsFromURL(url) {
		if (isShopeeWeb() || !url) {
			return null;
		}

		var valid = /^(http|https):\/\/[^ "]+$/;
		if (!valid.test(url)) {
			return null;
		}

		var urlObj = urlToLocation(url);
		var allParams = parse_all_params(url);
		// extract the path name out to reduce object property access
		var urlPathName = urlObj.pathname;

		var rnParams = {
			page: null,
			pathParams: _.extend({}, allParams.hash, allParams.search)
		};

		var mall_flash_sale_url = mallFlashSaleRe.test(urlPathName);
		if (mall_flash_sale_url) {
			url = url.replace('mall-flash-sale', 'brand_sale');
			var pathParams = {
				module: "TRANSFER_PAGE",
				navigate_url: url,
			};
			rnParams.page = 'brand_sale';
			rnParams.pathParams = pathParams;
			return rnParams;
		}


		// check if the url is redirected back from RN
		if (allParams.search['__dsrn__'] == 1) {
			return null;
		}
		
		// check coins reward page
		var coin_reward_page_url = coinsRewardPageRe.test(urlPathName);
		if (coin_reward_page_url) {
			url = url.replace('koin-shopee', 'shopee-coins')
			var pathParams = {
				module: "TRANSFER_PAGE",
				navigate_url: url,
			};
			rnParams.page = 'coin_reward_page';
			rnParams.pathParams = pathParams;
			return rnParams;
		}

		// check if the url is going to product page through seo item url.
		var itemArray = itemSEORe.exec(urlPathName);
		if (itemArray) {
			_.extend(rnParams.pathParams, {
				module: "PRODUCT_PAGE",
				shopid: itemArray[1],
				itemid: itemArray[2]
			});
			rnParams.page = 'product';
			return rnParams;
		}

		var itemArray = itemPCUrlRe.exec(urlPathName);
		if (itemArray) {
			_.extend(rnParams.pathParams, {
				module: "PRODUCT_PAGE",
				shopid: itemArray[1],
				itemid: itemArray[2]
			});
			rnParams.page = 'product';
			return rnParams;
		}

		// check if the url is going to product page through normal item url.
		var itemURL = itemRe.test(urlPathName);
		if (itemURL) {
			var parameter = parse_hash(urlObj.hash) || {};
			if (!parameter || !parameter.shopid || !parameter.itemid) {
				if (urlObj.search) {
					var query = urlObj.search.split("?")[1];
					var hashes = query.split("&");
					var vars = {};
					for (var i = 0; i < hashes.length; i++) {
						var hash = hashes[i].split("=");
						vars[hash[0]] = hash[1];
					}
					if ("sid" in vars && "iid" in vars) {
						parameter = {};
						parameter.shopid = vars["sid"];
						parameter.itemid = vars["iid"];
					}
					else if ("shopid" in vars && "itemid" in vars) {
						parameter = {};
						parameter.shopid = vars["shopid"];
						parameter.itemid = vars["itemid"];
					}
					if (parameter && "modelid" in vars) {
						parameter.modelid = vars["modelid"];
					}
				}
			}

			var pathParams = {
				shopid: parameter.shopid
			};

			if (parameter && parameter.snapshot) {
				pathParams.snapshot_id = parameter.itemid;
				pathParams.modelid = parameter.modelid;
				pathParams.module = "PRODUCT_SNAPSHOT_PAGE";
				rnParams.page = 'snapshot';
			} else {
				pathParams.itemid = parameter.itemid;
				pathParams.module = "PRODUCT_PAGE";
				rnParams.page = 'product';
			}

			rnParams.pathParams = pathParams;
			return rnParams;
		}

		// check if the url is going to shop page through normal shop url.
		var shopURL = shopRe.test(urlPathName);
		if (shopURL) {
			var parameter = parse_hash(urlObj.hash) || {};
			if (!parameter || !parameter.shopid) {
				if (urlObj.search) {
					var query = urlObj.search.split("?")[1];
					var hashes = query.split("&");
					var vars = {};
					for (var i = 0; i < hashes.length; i++) {
						var hash = hashes[i].split("=");
						vars[hash[0]] = hash[1];
					}
					if ("sid" in vars) {
						parameter = {};
						parameter.shopid = vars["sid"];
					}
					else if ("shopid" in vars) {
						parameter = {};
						parameter.shopid = vars["shopid"];
					}
					if (parameter && parameter.shopid && "shopcat_id" in vars) {
						parameter.shopcat_id = vars["shopcat_id"];
					}
					if (parameter && parameter.shopid && "tab" in vars) {
						parameter.tab = vars["tab"];
					}
				}
			}

			var pathParams = {
				module: "SHOP_PAGE",
				shopid: parameter.shopid,
				shopcat_id: parameter.shopcat_id,
				tab: parameter.tab
			};
			rnParams.page = 'shop';
			rnParams.pathParams = pathParams;
			return rnParams;
		}

		// check if the url is going to category page through seo category url.
		var categoryArray = categorySEORe.exec(urlPathName);
		if (categoryArray) {
			_.extend(rnParams.pathParams, {
				module: "CATEGORY_PAGE",
				catid: categoryArray[1]
			});
			rnParams.page = 'category';
			return rnParams;
		}

		// check if the url is going to sub category page through seo sub category url.
		var subCategoryArray = subCategorySEORe.exec(urlPathName);
		if (subCategoryArray) {
			_.extend(rnParams.pathParams, {
				module: "SEARCH_RESULT_PAGE",
				categoryid: subCategoryArray[1],
				sub_categoryid: subCategoryArray[2]
			});
			rnParams.page = 'search';
			return rnParams;
		}

		// check if the url is going to sub sub category page through seo sub sub category url.
		var subSubCategoryArray = subSubCategorySEORe.exec(urlPathName);
		if (subSubCategoryArray) {
			_.extend(rnParams.pathParams, {
				module: "SEARCH_RESULT_PAGE",
				categoryid: subSubCategoryArray[2],
				sub_categoryid: subSubCategoryArray[3],
				sub_sub_categoryid: subSubCategoryArray[4],
				search: subSubCategoryArray[1]
			});
			rnParams.page = 'search';
			return rnParams;
		}

		// check if the url is going to category page through normal category url.
		var categoryArray = categoryRe.exec(urlPathName);
		if (categoryArray) {
			_.extend(rnParams.pathParams, {
				module: "CATEGORY_PAGE",
				catid: categoryArray[1]
			});
			rnParams.page = 'category';
			return rnParams;
		}

		// check if the url is going to category item page through normal category url.
		var categoryItemURL = categoryItemRe.test(urlPathName);
		if (categoryItemURL) {
			_.extend(rnParams.pathParams, {
				module: "SEARCH_RESULT_PAGE"
			});
			rnParams.page = 'search';
			return rnParams;
		}

		// check if the url is going to search page through normal search-item url.
		var searchURL = searchRe.test(urlPathName);
		if (searchURL) {
			_.extend(rnParams.pathParams, {
				module: "SEARCH_RESULT_PAGE"
			});
			rnParams.page = 'search';
			return rnParams;
		}

		// voucher wallet landing page is same as search page
		var voucherWalletInviteArray = voucherInviteRe.exec(urlPathName);
		if (voucherWalletInviteArray) {
			var queryParams = { "promotionid": voucherWalletInviteArray[1], "voucher_code": safeDecodeURIComponent(voucherWalletInviteArray[2]) }
			var pathParams = {
				module: "SEARCH_RESULT_PAGE",
			};
			_.extend(pathParams, queryParams);
			rnParams.page = 'search';
			rnParams.pathParams = pathParams;
			return rnParams;
		}

		// check if the url is going to collections page through collection seo url.
		var collectionsSEOArray = collectionSEORe.exec(urlPathName);
		if (collectionsSEOArray) {
			_.extend(rnParams.pathParams, {
				module: "SEARCH_RESULT_PAGE",
				collection: collectionsSEOArray[1]
			});
			rnParams.page = 'collection';
			return rnParams;
		}

		// check if the url is going to flash sale landing page.
		var flash_sale_url = flashSaleUrlRe.test(urlPathName);
		if (flash_sale_url) {
			_.extend(rnParams.pathParams, {
				module: "FLASH_SALE_PAGE"
			});
			if (rnParams.pathParams.fromItem) {
				rnParams.pathParams.from_item = rnParams.pathParams.fromItem;
			}
			if (rnParams.pathParams.promotionId) {
				rnParams.pathParams.promotion_id = rnParams.pathParams.promotionId;
			}
			rnParams.page = 'flash_sale';
			return rnParams;
		}

		// check if the url is going to all campaigns page through normal url.
		var campaignsURL = campaignsRe.test(urlPathName);
		if (campaignsURL) {
			_.extend(rnParams.pathParams, {
				module: "CAMPAIGNS_PAGE"
			});
			rnParams.page = 'campaigns';
			return rnParams;
		}

		// check if the url is going to popular product page.
		var popularProductURL = popularProductRe.test(urlPathName);
		if (popularProductURL) {
			_.extend(rnParams.pathParams, {
				module: "RECOMMENDATION_MORE_PAGE",
				recommendType: Constants.RECOMMENDATION_TYPE.POPULAR
			});
			rnParams.page = 'popular_products';
			return rnParams;
		}

		// check if the url is going to daily discover product page.
		var dailyDiscoverURL = dailyDiscoverRe.test(urlPathName);
		if (dailyDiscoverURL) {
			_.extend(rnParams.pathParams, {
				module: "RECOMMENDATION_MORE_PAGE",
				recommendType: Constants.RECOMMENDATION_TYPE.DAILY_DISCOVER
			});
			rnParams.page = 'daily_discover';
			return rnParams;
		}

		// check if the url is going to just for you page
		var justForYouUrl = justForYouRe.test(urlPathName);
		if (justForYouUrl) {
			_.extend(rnParams.pathParams, {
				module: "RECOMMENDATION_MORE_PAGE",
				recommendType: Constants.RECOMMENDATION_TYPE.OFFICIAL_SHOP
			});
			if (rnParams.pathParams['catid'] !== undefined)
				rnParams.pathParams['catId'] = parseInt(rnParams.pathParams['catid']);
			rnParams.page = 'just_for_you';
			return rnParams;
		}
		// check if the url is going to bundle deal page.
		var bundleDealArray = bundleDealRe.exec(urlPathName);
		if (bundleDealArray) {
			_.extend(rnParams.pathParams, {
				module: "BUNDLE_DEAL_PAGE",
				bundleDealId: bundleDealArray[1]
			});
			rnParams.page = 'bundle_deal';
			return rnParams;
		}

		// RN buyer wallet landing page
		var buyerWalletUrl = buyerWalletRe.test(urlPathName);
		if (buyerWalletUrl) {
			_.extend(rnParams.pathParams, {
				module: "WALLET",
				page: "WALLET"
			});
			rnParams.page = 'wallet';
			return rnParams
		}

		// check if the url is going to referral home page.
		var referralUrl = referralRe.test(urlPathName);
		if (referralUrl) {
			_.extend(rnParams.pathParams, {
				module: "REFERRAL_PROGRAM_HOME"
			});
			rnParams.page = 'referral';
			return rnParams;
		}


		// check if the url is going to group invite page
		var groupInviteArray = groupInviteRe.exec(urlPathName);
		if (groupInviteArray) {
			_.extend(rnParams.pathParams, {
				module: "GROUP_BUY_GROUP_DETAIL",
				groupId: groupInviteArray[1]
			});
			rnParams.page = 'group_invite';
			return rnParams;
		}

		var shopSettingsUrl = shopSettingsRe.test(urlPathName);
		if (shopSettingsUrl) {
			_.extend(rnParams.pathParams, {
				module: "SHOP_SETTINGS_PAGE"
			});
			rnParams.page = 'shop_settings';
			return rnParams;
		}

		var groupBuyLandingPageGroupTab = groupBuyLandingPageGroupTabRe.test(urlPathName);
		if (groupBuyLandingPageGroupTab) {
			_.extend(rnParams.pathParams, {
				module: "GROUP_BUY_LANDING_PAGE",
				initTabIndex: 0
			});
			rnParams.page = 'group_buy_landing';
			return rnParams;
		}

		// check if the url is group buy landing page deal tab. It may end with or without a slash.
		var groupBuyLandingPageDealTabUrl = groupBuyLandingPageDealTabRe.test(urlPathName);
		if (groupBuyLandingPageDealTabUrl) {
			_.extend(rnParams.pathParams, {
				module: "GROUP_BUY_LANDING_PAGE",
				initTabIndex: 1
			});
			rnParams.page = 'group_buy_landing';
			return rnParams;
		}

		// Open RN mall without catid
		var officialShopUrl = officialShopRe.test(urlPathName);
		if (officialShopUrl) {
			var queryParams = parse_url_general('?', urlObj.search);
			if (queryParams && queryParams['diable_rn'])
				return rnParams;
			var pathParams = {
				module: "MALL_PAGE_LANDING",
			};
			rnParams.pathParams = pathParams;
			rnParams.page = 'official_shops';
			return rnParams
		}

		// Open RN mall with catid
		var officialShopArray = officialShopSEORe.exec(urlPathName);
		if (officialShopArray) {
			var queryParams = parse_url_general('?', urlObj.search);
			if (queryParams && queryParams['diable_rn'])
				return rnParams;
			var pathParams = {
				module: "MALL_PAGE_LANDING",
				catid: officialShopArray[1],
			};
			rnParams.pathParams = pathParams;
			rnParams.page = 'official_shops';
			return rnParams;
		}

		// check if the url is going to similar products home page.
		var similarProductsUrl = similarProductsRe.test(urlPathName);
		if (similarProductsUrl) {
			var pathParams = {
				module: "FIND_SIMILAR_PRODUCTS",
			};
			var queryParams = parse_url_general('?', urlObj.search);
			rnParams.page = 'similar_products';
			rnParams.pathParams = _.extend(pathParams, queryParams);
			return rnParams;
		}

		var voucherWalletUrl = voucherWalletRe.test(urlPathName);
		var voucherWalletUniversalLinkUrl = voucherWalletUniversalLinkRe.test(urlPathName);
		if (voucherWalletUrl || voucherWalletUniversalLinkUrl) {
			_.extend(rnParams.pathParams, {
				module: "VOUCHER_WALLET_HOME_PAGE"
			});
			rnParams.page = 'voucher_wallet_home';
			return rnParams;
		}

		var micrositeUrl = micrositeRe.test(urlPathName);
		var walletsiteUrl = walletsiteRe.test(urlPathName);
		var bankAccountsUrl = bankAccountsRe.test(urlPathName);
		var otpVerifyUrl = otpVerifyRe.test(urlPathName);  // Refer to JIRA SPAY-5998 for detail
		if (micrositeUrl || walletsiteUrl || bankAccountsUrl || otpVerifyUrl) {
			var pathParams = {
				module: "TRANSFER_PAGE",
				navigate_url: url,
			};
			rnParams.page = 'microsite';
			rnParams.pathParams = pathParams;
			return rnParams;
		}

		for (var index in transferPageConfigs) {
			if (!transferPageConfigs.hasOwnProperty(index)) {
				continue;
			}
			var transferPageConfig = transferPageConfigs[index];
			var minRnVersion = transferPageConfig["minRnVersion"] || 0;
			var transferPageRes = transferPageConfig["transferPageRes"];
			if (getRnVersion() < minRnVersion || !transferPageRes) {
				continue;
			}

			for (var i in transferPageRes) {
				if (!transferPageRes.hasOwnProperty(i)) {
					continue;
				}
				if (transferPageRes[i].test(urlPathName)) {
					var pathParams = {
						module: "TRANSFER_PAGE",
						navigate_url: url,
					};
					rnParams.page = transferPageConfig["featureName"];
					rnParams.pathParams = pathParams;
					return rnParams;
				}
			}
		}

		var slashPriceLandingPageUrl = slashPriceLandingPageRe.test(urlPathName);
		if (slashPriceLandingPageUrl) {
			_.extend(rnParams.pathParams, {
				module: "SLASH_PRICE_LANDING_PAGE"
			});
			rnParams.page = 'slash_price_landing_page';
			return rnParams;
		}
		// ### End of mapping rules ### //
		return rnParams;
	}

	function jumpToReactNativeIfExists(url, popSelf, dryRun) {
		var urlObj = urlToLocation(url);
		var regex = new RegExp("^" + window.MARKET_UNIVERSAL_LANDING_PAGE_PREFIX, 'g');
		urlObj.pathname = urlObj.pathname.replace(regex, '');
		url = urlObj.href;
		url = processAdsAffiliationUrl(url);
		var rnParams = getRNParamsFromURL(url);

		if (rnParams && rnParams.page && BJUtil.isRNEnabled(rnParams.page)) {
			if (!dryRun) {
				bridgeInit(function () {
					BJUtil.navigateReactNative(rnParams.pathParams, popSelf || false);
				});
			}
			return true;
		}
		return false;
	}

	function init() {
		// do this in every page before loading.
		bridgeInit(function () {
			jumpToReactNativeIfExists(window.location.href, true);
		});
	}


	// We need to wait all constant defined in js file loaded. (eg: TRACKING_URL_PARAMS)
	setTimeout(init, 0);

	return {
		jumpToReactNativeIfExists: jumpToReactNativeIfExists,
		getRNParamsFromURL: getRNParamsFromURL,
	};

})();
