File: shopping_service.h

package info (click to toggle)
chromium 139.0.7258.127-1
  • links: PTS, VCS
  • area: main
  • in suites:
  • size: 6,122,068 kB
  • sloc: cpp: 35,100,771; ansic: 7,163,530; javascript: 4,103,002; python: 1,436,920; asm: 946,517; xml: 746,709; pascal: 187,653; perl: 88,691; sh: 88,436; objc: 79,953; sql: 51,488; cs: 44,583; fortran: 24,137; makefile: 22,147; tcl: 15,277; php: 13,980; yacc: 8,984; ruby: 7,485; awk: 3,720; lisp: 3,096; lex: 1,327; ada: 727; jsp: 228; sed: 36
file content (730 lines) | stat: -rw-r--r-- 30,540 bytes parent folder | download | duplicates (3)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
// Copyright 2022 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef COMPONENTS_COMMERCE_CORE_SHOPPING_SERVICE_H_
#define COMPONENTS_COMMERCE_CORE_SHOPPING_SERVICE_H_

#include <map>
#include <memory>
#include <string>
#include <tuple>
#include <unordered_set>
#include <utility>
#include <vector>

#include "base/cancelable_callback.h"
#include "base/containers/flat_set.h"
#include "base/functional/callback.h"
#include "base/memory/raw_ptr.h"
#include "base/memory/scoped_refptr.h"
#include "base/memory/weak_ptr.h"
#include "base/scoped_observation.h"
#include "base/scoped_observation_traits.h"
#include "base/sequence_checker.h"
#include "base/supports_user_data.h"
#include "components/commerce/core/account_checker.h"
#include "components/commerce/core/commerce_info_cache.h"
#include "components/commerce/core/commerce_types.h"
#include "components/commerce/core/compare/cluster_manager.h"
#include "components/commerce/core/product_specifications/product_specifications_cache.h"
#include "components/commerce/core/product_specifications/product_specifications_service.h"
#include "components/commerce/core/product_specifications/product_specifications_set.h"
#include "components/commerce/core/proto/cart_db_content.pb.h"
#include "components/commerce/core/proto/commerce_subscription_db_content.pb.h"
#include "components/commerce/core/proto/discount_infos_db_content.pb.h"
#include "components/commerce/core/proto/discounts_db_content.pb.h"
#include "components/commerce/core/proto/parcel_tracking_db_content.pb.h"
#include "components/commerce/core/subscriptions/commerce_subscription.h"
#include "components/commerce/core/web_extractor.h"
#include "components/history/core/browser/history_service.h"
#include "components/history/core/browser/history_service_observer.h"
#include "components/keyed_service/core/keyed_service.h"
#include "components/optimization_guide/core/hints/optimization_guide_decision.h"
#include "components/unified_consent/consent_throttle.h"
#include "services/data_decoder/public/cpp/data_decoder.h"
#include "services/metrics/public/cpp/ukm_source_id.h"

class GURL;
class PrefService;

template <typename T>
class SessionProtoStorage;

namespace base {
class Value;
}

namespace bookmarks {
class BookmarkModel;
class BookmarkNode;
}  // namespace bookmarks

namespace network {
class SharedURLLoaderFactory;
}  // namespace network

namespace optimization_guide {
class OptimizationGuideDecider;
class OptimizationMetadata;
}  // namespace optimization_guide

namespace power_bookmarks {
class PowerBookmarkService;
}  // namespace power_bookmarks

namespace sessions {
class TabRestoreService;
}  // namespace sessions

namespace signin {
class IdentityManager;
}  // namespace signin

namespace syncer {
class SyncService;
}  // namespace syncer

namespace commerce {

extern const char kImageAvailabilityHistogramName[];
extern const char kProductInfoLocalExtractionTime[];

// The amount of time to wait after the last "stopped loading" event to run the
// on-page extraction for product info.
extern const uint64_t kProductInfoLocalExtractionDelayMs;

// The availability of the product image for an offer. This needs to be kept in
// sync with the ProductImageAvailability enum in enums.xml.
enum class ProductImageAvailability {
  kServerOnly = 0,
  kLocalOnly = 1,
  kBothAvailable = 2,
  kNeitherAvailable = 3,
  kMaxValue = kNeitherAvailable,
};

// The type of fallback data can be used when generating product info.
enum class ProductInfoFallback {
  kTitle = 0,
  kLeadImage = 1,
  kFallbackImage = 2,
  kPrice = 3,
  kMaxValue = kPrice,
};

namespace metrics {
class ScheduledMetricsManager;
}  // namespace metrics

class BookmarkUpdateManager;
class DiscountInfosStorage;
class ProductSpecificationsServerProxy;
class ProductSpecificationsService;
class ShoppingPowerBookmarkDataProvider;
class ShoppingBookmarkModelObserver;
class SubscriptionsManager;
class SubscriptionsObserver;
class WebWrapper;
enum class SubscriptionType;
struct CommerceSubscription;

// Types of shopping pages from backend.
enum class ShoppingPageType {
  kUnknown = 0,
  kShoppingPage = 1,
  kMerchantDomainPage = 2,
  kMultiProductPage = 3,
  kSingleProductPage = 4,
  kProductReviewPage = 5,
  kProductComparisonPage = 6,
  kProductTopNPage = 7,
  kSoldOutPage = 8,
  kBuyingGuidePage = 9,
  kMaxValue = kBuyingGuidePage,
};

using DiscountsPair = std::pair<GURL, std::vector<DiscountInfo>>;
using DiscountsOptGuideCallback = base::OnceCallback<void(DiscountsPair)>;
using RepeatingProductInfoCallback =
    base::RepeatingCallback<void(const GURL&,
                                 const std::optional<const ProductInfo>&)>;

// A callback for getting updated ProductInfo for a bookmark. This provides the
// bookmark ID being updated, the URL, and the product info.
using BookmarkProductInfoUpdatedCallback = base::RepeatingCallback<
    void(const int64_t, const GURL&, std::optional<ProductInfo>)>;

using UrlProductIdentifierTuple =
    std::tuple<const GURL, const std::optional<const uint64_t>>;

using UrlProductIdentifierTupleCallback =
    base::OnceCallback<void(const UrlProductIdentifierTuple&)>;

// Under Desktop browser test or interactive ui test, use
// ShoppingServiceFactory::SetTestingFactory to create a
// MockShoppingService for testing. The test should use
// BrowserContextDependencyManager to register a callback to create the
// MockShoppingService when the BrowserContext is created.
//
// Example of an InteractiveBrowserTest setup for using a MockShoppingService:
//
// clang-format off
// #include "components/commerce/core/mock_shopping_service.h"
// #include "components/keyed_service/content/browser_context_dependency_manager.h"
//
// class MyTest : public InteractiveBrowserTest {
//   void SetUpInProcessBrowserTestFixture() override {
//     create_services_subscription_ =
//         BrowserContextDependencyManager::GetInstance()
//             ->RegisterCreateServicesCallbackForTesting(base::BindRepeating(
//                 &MyTest::OnWillCreateBrowserContextServices,
//                 weak_ptr_factory_.GetWeakPtr()));
//   }
//
//   void OnWillCreateBrowserContextServices(content::BrowserContext* context) {
//     commerce::ShoppingServiceFactory::GetInstance()->SetTestingFactory(
//         context, base::BindRepeating([](content::BrowserContext* context) {
//           return commerce::MockShoppingService::Build();
//         }));
//   }
//
//  private:
//   base::CallbackListSubscription create_services_subscription_;
//   base::WeakPtrFactory<MyTest> weak_ptr_factory_{this};
// };
//
// To get the MockShoppingService:
// auto* mock_shopping_service = static_cast<commerce::MockShoppingService*>(
//     commerce::ShoppingServiceFactory::GetForBrowserContext(
//         browser()->profile()));
// clang-format on

class ShoppingService : public KeyedService,
                        public base::SupportsUserData,
                        public history::HistoryServiceObserver,
                        public ProductSpecificationsSet::Observer {
 public:
  ShoppingService(
      const std::string& country_on_startup,
      const std::string& locale_on_startup,
      bookmarks::BookmarkModel* bookmark_model,
      optimization_guide::OptimizationGuideDecider* opt_guide,
      PrefService* pref_service,
      signin::IdentityManager* identity_manager,
      syncer::SyncService* sync_service,
      scoped_refptr<network::SharedURLLoaderFactory> url_loader_factory,
      SessionProtoStorage<
          commerce_subscription_db::CommerceSubscriptionContentProto>*
          subscription_proto_db,
      power_bookmarks::PowerBookmarkService* power_bookmark_service,
      ProductSpecificationsService* product_specifications_service,
      SessionProtoStorage<discounts_db::DiscountsContentProto>*
          discounts_proto_db,
      SessionProtoStorage<cart_db::ChromeCartContentProto>* cart_proto_db,
      SessionProtoStorage<discount_infos_db::DiscountInfosContentProto>*
          discount_infos_db,
      SessionProtoStorage<parcel_tracking_db::ParcelTrackingContent>*
          parcel_tracking_proto_db,
      history::HistoryService* history_service,
      std::unique_ptr<commerce::WebExtractor> web_extractor,
      sessions::TabRestoreService* tab_restore_service);
  ~ShoppingService() override;

  ShoppingService(const ShoppingService&) = delete;
  ShoppingService& operator=(const ShoppingService&) = delete;

  // Gets an AccountChecker instance to aid in determining feature eligibility.
  virtual AccountChecker* GetAccountChecker();

  // This API retrieves the product information for the provided |url| and
  // passes the payload back to the caller via |callback|. At minimum, this
  // API will wait for data from the backend but may provide a "partial" result
  // that doesn't include information from the page on-device.
  virtual void GetProductInfoForUrl(const GURL& url,
                                    ProductInfoCallback callback);

  // Attempts to retrieve product info for all of the URLs provided in |urls|.
  // This API behaves the same as |GetProductInfoForUrl| with the exception of
  // how on-demand requests are handled - rather than fetching individually,
  // they are batched. The entire set of info is provided to the callback once
  // complete.
  virtual void GetProductInfoForUrls(const std::vector<GURL>& urls,
                                     ProductInfoBatchCallback callback);

  // This API returns whatever product information is currently available for
  // the specified |url|. This method is less reliable than GetProductInfoForUrl
  // above as it may return an empty or partial result prior to the page being
  // processed or information being available from the backend.
  virtual std::optional<ProductInfo> GetAvailableProductInfoForUrl(
      const GURL& url);

  // Get updated product info (including price) for the provided list of
  // bookmark IDs. The information for each bookmark will be provided via a
  // repeating callback that provides the bookmark's ID, URL, and product info.
  // Currently this API should only be used in the BookmarkUpdateManager.
  virtual void GetUpdatedProductInfoForBookmarks(
      const std::vector<int64_t>& bookmark_ids,
      BookmarkProductInfoUpdatedCallback info_updated_callback);

  // Gets the maximum number of bookmarks that the backend will retrieve per
  // call to |GetUpdatedProductInfoForBookmarks|. This limit is imposed by our
  // backend rather than the shopping service itself.
  virtual size_t GetMaxProductBookmarkUpdatesPerBatch();

  // This API fetches information about a merchant for the provided |url| and
  // passes the payload back to the caller via |callback|. Call will run after
  // the fetch is completed. The merchant info object will be null if there is
  // none available.
  virtual void GetMerchantInfoForUrl(const GURL& url,
                                     MerchantInfoCallback callback);

  // This API fetches price insights information of the product on the provided
  // |url| and passes the payload back to the caller via |callback|. Call will
  // run after the fetch is completed. The price insights info object will be
  // null if there is none available.
  virtual void GetPriceInsightsInfoForUrl(const GURL& url,
                                          PriceInsightsInfoCallback callback);

  // This API fetches valid discounts information on the provided |url| and
  // passes the payload back to the caller via |callback|. Call will run after
  // the fetch is completed.
  virtual void GetDiscountInfoForUrl(const GURL& url,
                                     DiscountInfoCallback callback);

  // This API fetches available valid discounts information on the provided
  // |url| and passes the payload back to the caller via |callback|.
  // Call will run after the fetch is completed.
  virtual void GetAvailableDiscountInfoForUrl(const GURL& url,
                                          DiscountInfoCallback callback);

  virtual void GetProductSpecificationsForUrls(
      const std::vector<GURL>& urls,
      ProductSpecificationsCallback callback);

  // This API fetches whether the provided |url| is a shopping-related page and
  // passes the result back to the caller via |callback|. Call will run after
  // the fetch is completed.
  virtual void IsShoppingPage(const GURL& url, IsShoppingPageCallback callback);

  // Create new subscriptions in batch if needed, and will notify |callback| if
  // the operation completes successfully.
  virtual void Subscribe(
      std::unique_ptr<std::vector<CommerceSubscription>> subscriptions,
      base::OnceCallback<void(bool)> callback);

  // Delete existing subscriptions in batch if needed, and will notify
  // |callback| if the operation completes successfully.
  virtual void Unsubscribe(
      std::unique_ptr<std::vector<CommerceSubscription>> subscriptions,
      base::OnceCallback<void(bool)> callback);

  // Gets all subscriptions for the specified type. The list of subscriptions
  // will be provided as input to the |callback| passed to this function.
  virtual void GetAllSubscriptions(
      SubscriptionType type,
      base::OnceCallback<void(std::vector<CommerceSubscription>)> callback);

  // Methods to register or remove SubscriptionsObserver, which will be notified
  // when a (un)subscribe request has finished.
  void AddSubscriptionsObserver(SubscriptionsObserver* observer);
  void RemoveSubscriptionsObserver(SubscriptionsObserver* observer);

  // Check if the specified subscription exists.
  virtual void IsSubscribed(CommerceSubscription subscription,
                            base::OnceCallback<void(bool)> callback);

  // Checks if a subscription exists from the in-memory cache. Use of the the
  // callback-based version |IsSubscribed| is preferred. Information provided
  // by this API is not guaranteed to be correct.
  virtual bool IsSubscribedFromCache(const CommerceSubscription& subscription);

  // Gets all bookmarks that are price tracked. Internally this calls the
  // function by the same name in price_tracking_utils.h.
  virtual void GetAllPriceTrackedBookmarks(
      base::OnceCallback<void(std::vector<const bookmarks::BookmarkNode*>)>
          callback);

  // Gets all bookmarks that have shopping information associated with them.
  // Internally this calls the function by the same name in
  // price_tracking_utils.h.
  virtual std::vector<const bookmarks::BookmarkNode*> GetAllShoppingBookmarks();

  // Fetch users' pref from server on whether to receive price tracking emails.
  void FetchPriceEmailPref();

  // Schedule an update for saved product bookmarks using
  // |bookmark_update_manager_|.
  virtual void ScheduleSavedProductUpdate();

  // Returns whether a feature that is restricted to a specific region and
  // locale is enabled. This method is a proxy for the utility method by the
  // same name in commerce_feature_list but provides the country and locale as
  // determined by this service at startup.
  bool IsRegionLockedFeatureEnabled(
      const base::Feature& feature,
      const base::Feature& region_specific_feature);

  // This is a feature check for the "shopping list". This will only return true
  // if the user has the feature flag enabled, is signed-in, has MSBB enabled,
  // has webapp activity enabled, is allowed by enterprise policy, and (if
  // applicable) in an eligible country and locale. The value returned by this
  // method can change at runtime, so it should not be used when deciding
  // whether to create critical, feature-related infrastructure.
  virtual bool IsShoppingListEligible();

  // Wait for the shopping service and all of its dependent components to be
  // ready before attempting to access different features. This can be used for
  // UI that is available shortly after startup. If the dependencies time out or
  // the browser is being shut down, a null pointer to the shopping service will
  // be passed to the callback.
  virtual void WaitForReady(
      base::OnceCallback<void(ShoppingService*)> callback);

  // Returns a list of URLs corresponding to active WebWrappers the shopping
  // service is keeping track of. This does not map to open tabs across all
  // platforms. Excludes non-HTTP/HTTPS URLs.
  virtual const std::vector<UrlInfo> GetUrlInfosForActiveWebWrappers();

  // Returns a list of URL info provided by |GetUrlInfosForActiveWebWrappers|
  // but filtered by URLs that are associated with products.
  virtual void GetUrlInfosForWebWrappersWithProducts(
      base::OnceCallback<void(const std::vector<UrlInfo>)> callback);

  // Gets a list of URLs from web wrappers that were recently viewed by the
  // user (ordered by most recent first). This generally aligns with recently
  // viewed tabs.
  virtual const std::vector<UrlInfo> GetUrlInfosForRecentlyViewedWebWrappers();

  virtual ProductSpecificationsService* GetProductSpecificationsService();

  virtual ClusterManager* GetClusterManager();

  // history::HistoryServiceObserver:
  void OnHistoryDeletions(history::HistoryService* history_service,
                          const history::DeletionInfo& deletion_info) override;

  // ProductSpecificationsSet::Observer:
  void OnProductSpecificationsSetRemoved(
      const ProductSpecificationsSet& set) override;

  // Get a weak pointer for this service instance.
  base::WeakPtr<ShoppingService> AsWeakPtr();

  void Shutdown() override;

 private:
  // "CommerceTabHelper" encompases both the content/ and ios/ versions.
  friend class CommerceTabHelper;
  friend class CommerceInternalsHandler;
  // Test classes are also friends.
  friend class ShoppingServiceTestBase;
  friend class ShoppingServiceTest;
  // TODO(b/362316113): Pass HistoryService through handler constructor instead
  // of having the handler as a friend.
  friend class ShoppingServiceHandler;

  // A notification that a WebWrapper has been created. This typically
  // corresponds to a user creating a tab.
  void WebWrapperCreated(WebWrapper* web);

  // A notification that a WebWrapper has been destroyed. This signals that the
  // web page backing the provided WebWrapper is about to be destroyed.
  // Typically corresponds to a user closing a tab.
  void WebWrapperDestroyed(WebWrapper* web);

  // A notification that a web wrapper finished a navigation in the primary
  // main frame.
  void DidNavigatePrimaryMainFrame(WebWrapper* web);

  // Handle main frame navigation for the product info API.
  void HandleDidNavigatePrimaryMainFrameForProductInfo(WebWrapper* web);

  // A notification that the user navigated away from the |from_url|.
  void DidNavigateAway(WebWrapper* web, const GURL& from_url);

  // A notification that the provided web wrapper has stopped loading. This does
  // not necessarily correspond to the page being completely finished loading
  // and is a useful signal to help detect and deal with single-page web apps.
  void DidStopLoading(WebWrapper* web);

  // A notification that the provided web wrapper has finished loading its main
  // frame.
  void DidFinishLoad(WebWrapper* web);

  // A notification that the active web wrapper was switched. This signal is
  // analogous to switching tabs.
  void OnWebWrapperSwitched(WebWrapper* web);

  // Called to signal that a WebWrapper is viewed. This happens when a new
  // navigation is committed in a focused tab.
  void OnWebWrapperViewed(WebWrapper* web);

  // Schedule (or reschedule) the on-page local extraction execution. Calling
  // this sequentially for the same web wrapper with the same URL will cancel
  // the pending task and schedule a new one. The script will, at most, run once
  // per unique navigation.
  void ScheduleProductInfoLocalExtraction(WebWrapper* web);

  // Check conditions to decide if the on-page info extraction should be run and
  // trigger the run if needed.
  void TryRunningLocalExtractionForProductInfo(base::WeakPtr<WebWrapper> web);

  // Actually run the on-page info extraction if the page is shopping page based
  // on `is_shopping_page`.
  void RunLocalExtractionForProductInfoForShoppingPage(
      base::WeakPtr<WebWrapper> web,
      const GURL& url,
      std::optional<bool> is_shopping_page);

  // A callback for recording metrics after page navigation and having
  // determined the page is shopping related.
  void PDPMetricsCallback(
      bool is_off_the_record,
      optimization_guide::OptimizationGuideDecision decision,
      const optimization_guide::OptimizationMetadata& metadata,
      const GURL& url);

  // The internal impl that supports the different variations of the public
  // ProductInfo APIs.
  void GetProductInfoForUrlInternal(const GURL& url,
                                    ProductInfoCallback callback,
                                    bool attempt_on_demand_fetch);

  void HandleOptGuideProductInfoResponse(
      const GURL& url,
      WebWrapper* web,
      ProductInfoCallback callback,
      bool attempt_on_demand,
      optimization_guide::OptimizationGuideDecision decision,
      const optimization_guide::OptimizationMetadata& metadata);

  // Handle a response from the optimization guide on-demand API for product
  // info, specifically dealing with batch updates for bookmarks.
  void HandleOnDemandProductInfoResponseForBookmarks(
      BookmarkProductInfoUpdatedCallback callback,
      std::unordered_map<std::string, int64_t> url_to_id_map,
      const GURL& url,
      const base::flat_map<
          optimization_guide::proto::OptimizationType,
          optimization_guide::OptimizationGuideDecisionWithMetadata>&
          decisions);

  // Handle a generic on-demand request for product info. While this method
  // accepts a repeating callback, it should only ever be called once.
  void HandleOnDemandProductInfoResponse(
      RepeatingProductInfoCallback callback,
      const GURL& url,
      const base::flat_map<
          optimization_guide::proto::OptimizationType,
          optimization_guide::OptimizationGuideDecisionWithMetadata>&
          decisions);

  // Handles the on-demand part of |GetProductInfoForUrls|, waiting for all
  // fetches to complete before executing the callback.
  void DoOnDemandFetchForProductInfoUrlBatch(
      std::vector<GURL> urls,
      std::map<GURL, std::optional<ProductInfo>> info_map,
      ProductInfoBatchCallback callback);

  // Process the result of an on-demand request for product info and handle any
  // related cache maintenance.
  std::optional<ProductInfo> HandleAndStoreProductInfoFromOnDemand(
      const GURL& url,
      const base::flat_map<
          optimization_guide::proto::OptimizationType,
          optimization_guide::OptimizationGuideDecisionWithMetadata>&
          decisions);

  // Handle the result of running the local extraction fallback for product
  // info.
  void OnProductInfoLocalExtractionResult(const GURL url,
                                          ukm::SourceId source_id,
                                          base::Value result);

  // Tries to determine whether a page is a PDP only from information in meta
  // tags extracted from the page. If enough information is present to call the
  // page a PDP, this function returns true.
  static bool CheckIsPDPFromMetaOnly(const base::Value::Dict& on_page_meta_map);

  // Merge shopping data from existing |info| and the result of on-page
  // heuristics -- a JSON object holding key -> value pairs (a map) stored in
  // |on_page_data_map|. The merged data is written to |info|.
  static void MergeProductInfoData(ProductInfo* info,
                                   const base::Value::Dict& on_page_data_map);

  void HandleOptGuideMerchantInfoResponse(
      const GURL& url,
      MerchantInfoCallback callback,
      optimization_guide::OptimizationGuideDecision decision,
      const optimization_guide::OptimizationMetadata& metadata);

  // Update the data stored in the cache.
  void UpdateProductInfoCache(const GURL& url,
                              bool needs_js,
                              std::unique_ptr<ProductInfo> info);

  // Get the data stored in the cache or nullptr if none exists.
  const ProductInfo* GetFromProductInfoCache(const GURL& url);

  void HandleOptGuidePriceInsightsInfoResponse(
      const GURL& url,
      PriceInsightsInfoCallback callback,
      optimization_guide::OptimizationGuideDecision decision,
      const optimization_guide::OptimizationMetadata& metadata);

  std::unique_ptr<PriceInsightsInfo> OptGuideResultToPriceInsightsInfo(
      const optimization_guide::OptimizationMetadata& metadata);

  // Handle main frame navigation for the price insights info API.
  void HandleDidNavigatePrimaryMainFrameForPriceInsightsInfo(WebWrapper* web);

  void HandleOptGuideShoppingPageTypesResponse(
      const GURL& url,
      IsShoppingPageCallback callback,
      optimization_guide::OptimizationGuideDecision decision,
      const optimization_guide::OptimizationMetadata& metadata);

  void GetDiscountInfoFromOptGuide(const GURL& url,
                                   DiscountInfoCallback callback);

  void HandleOptGuideDiscountInfoResponse(
      const GURL& url,
      DiscountInfoCallback callback,
      optimization_guide::OptimizationGuideDecision decision,
      const optimization_guide::OptimizationMetadata& metadata);

  std::vector<DiscountInfo> OptGuideResultToDiscountInfos(
      const optimization_guide::OptimizationMetadata& metadata);

  void OnGetAllDiscountsFromOptGuide(const std::vector<GURL>& urls,
                                     DiscountInfoCallback callback,
                                     const std::vector<DiscountsPair>& results);

  void GetProductIdentifierForUrl(const GURL& url,
                                  UrlProductIdentifierTupleCallback callback);

  void UpdateRecentlyViewedURL(WebWrapper* web);

  // Return all ProductSpecificationsSets from ProductSpecificationsService.
  virtual const std::vector<ProductSpecificationsSet>
  GetAllProductSpecificationSets();

  void OnGetOnDemandProductInfo(const GURL& url,
                                const std::optional<const ProductInfo>& info);

  // The two-letter country code as detected on startup.
  std::string country_on_startup_;

  // The locale as detected on startup.
  std::string locale_on_startup_;

  // A handle to optimization guide for information about URLs that have
  // recently been navigated to.
  raw_ptr<optimization_guide::OptimizationGuideDecider> opt_guide_;

  raw_ptr<PrefService> pref_service_;

  raw_ptr<syncer::SyncService> sync_service_;

  const raw_ptr<bookmarks::BookmarkModel> bookmark_model_;

  std::unique_ptr<AccountChecker> account_checker_;

  std::unique_ptr<SubscriptionsManager> subscriptions_manager_;

  raw_ptr<power_bookmarks::PowerBookmarkService> power_bookmark_service_;

  raw_ptr<ProductSpecificationsService> product_specifications_service_;

  // The service's means of observing the bookmark model which is automatically
  // removed from the model when destroyed. This will be null if no
  // BookmarkModel is provided to the service.
  std::unique_ptr<ShoppingBookmarkModelObserver> shopping_bookmark_observer_;

  // The service's means of providing data to power bookmarks.
  std::unique_ptr<ShoppingPowerBookmarkDataProvider>
      shopping_power_bookmark_data_provider_;

  // The object handling discounts storage.
  std::unique_ptr<DiscountInfosStorage> discount_infos_storage_;

  // A cache that retains commerce information for a URL as long as at least one
  // instance of the URL is open in a tab or mainteined by some other subsystem.
  CommerceInfoCache commerce_info_cache_;

  ProductSpecificationsCache product_specifications_cache_;

  std::unique_ptr<ProductSpecificationsServerProxy> product_specs_server_proxy_;

  std::unique_ptr<BookmarkUpdateManager> bookmark_update_manager_;

  // The object tracking metrics that are recorded at specific intervals.
  std::unique_ptr<commerce::metrics::ScheduledMetricsManager>
      scheduled_metrics_manager_;

  // A consent throttle that will hold callbacks until the specific consent is
  // obtained.
  unified_consent::ConsentThrottle bookmark_consent_throttle_;

  // The object for local extractions of commerce information.
  std::unique_ptr<commerce::WebExtractor> web_extractor_;

  std::unordered_set<WebWrapper*> open_web_wrappers_;

  // A list of UrlInfo ordered by most recently viewed. This is based on
  // selected tab (not necessarily navigation).
  std::vector<UrlInfo> recently_visited_tabs_;

  // Class for clustering products.
  std::unique_ptr<ClusterManager> cluster_manager_;

  // An observer of the ProductSpecificationsService that keeps track of the
  // URLs contained within each ProductSpecificationsSet. This is used to keep
  // the commerce info cache up to date.
  std::unique_ptr<ProductSpecificationsSet::Observer>
      prod_spec_url_ref_observer_;

  // Map between URL and a list of callbacks that are waiting for product info.
  // This is used to avoid repeated calls to get product info for the same URL.
  std::map<GURL, std::vector<ProductInfoCallback>>
      on_demand_product_info_callbacks_;

  base::ScopedObservation<history::HistoryService,
                          history::HistoryServiceObserver>
      history_service_observation_{this};

  const raw_ptr<sessions::TabRestoreService> tab_restore_service_{nullptr};

  base::ScopedObservation<ProductSpecificationsService,
                          ProductSpecificationsSet::Observer>
      product_specifications_observation_{this};

  base::CancelableTaskTracker cancelable_task_tracker_;

  // Ensure certain functions are being executed on the same thread.
  SEQUENCE_CHECKER(sequence_checker_);

  base::WeakPtrFactory<ShoppingService> weak_ptr_factory_;
};

}  // namespace commerce

namespace base {

template <>
struct ScopedObservationTraits<commerce::ShoppingService,
                               commerce::SubscriptionsObserver> {
  static void AddObserver(commerce::ShoppingService* source,
                          commerce::SubscriptionsObserver* observer) {
    source->AddSubscriptionsObserver(observer);
  }
  static void RemoveObserver(commerce::ShoppingService* source,
                             commerce::SubscriptionsObserver* observer) {
    source->RemoveSubscriptionsObserver(observer);
  }
};

}  // namespace base

#endif  // COMPONENTS_COMMERCE_CORE_SHOPPING_SERVICE_H_