// Copyright 2025 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#ifndef CONTENT_BROWSER_WEBID_NAVIGATION_INTERCEPTOR_H_
#define CONTENT_BROWSER_WEBID_NAVIGATION_INTERCEPTOR_H_

#include "base/functional/callback.h"
#include "base/memory/weak_ptr.h"
#include "content/browser/webid/request_service.h"
#include "content/common/content_export.h"
#include "content/public/browser/navigation_controller.h"
#include "content/public/browser/navigation_throttle.h"
#include "content/public/browser/weak_document_ptr.h"
#include "mojo/public/cpp/bindings/remote.h"
#include "net/http/structured_headers.h"
#include "services/data_decoder/public/cpp/data_decoder.h"
#include "third_party/blink/public/mojom/webid/federated_request.mojom.h"
#include "url/gurl.h"

namespace content {

class NavigationThrottleRegistry;
class RenderFrameHost;
class NavigationHandle;

namespace webid {

// The NavigationInterceptor enables Identity Providers to control
// navigations to their endpoints by cancelling it and replacing it
// with an inline FedCM flow instead.
class CONTENT_EXPORT NavigationInterceptor
    : public content::NavigationThrottle {
 public:
  class RequestBuilder {
   public:
    ~RequestBuilder() = default;
    CONTENT_EXPORT std::optional<
        std::vector<blink::mojom::IdentityProviderGetParametersPtr>>
    Build(const GURL& base_url, net::structured_headers::Dictionary dictionary);
  };

  class ResponseBuilder {
   public:
    ResponseBuilder() = default;
    CONTENT_EXPORT std::optional<NavigationController::LoadURLParams> Build(
        const base::Value& response);
  };

  using RequestInitiator = base::RepeatingCallback<bool(
      RenderFrameHost* rfh,
      std::vector<blink::mojom::IdentityProviderGetParametersPtr>
          idp_get_params,
      ::password_manager::CredentialMediationRequirement requirement,
      NavigationHandle* navigation_handle,
      const GURL& intercepted_url,
      Request::RequestTokenCallback callback)>;

  explicit NavigationInterceptor(NavigationThrottleRegistry& registry);
  NavigationInterceptor(NavigationThrottleRegistry& registry,
                        RequestInitiator request_initiator);
  ~NavigationInterceptor() override;

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

  // NavigationThrottle overrides:
  ThrottleCheckResult WillStartRequest() override;
  ThrottleCheckResult WillRedirectRequest() override;
  ThrottleCheckResult WillProcessResponse() override;
  const char* GetNameForLogging() override;

  static void MaybeCreateAndAdd(NavigationThrottleRegistry& registry);

 private:
  ThrottleCheckResult ProcessRequest(const GURL& intercepted_url);

  void OnHeaderParsed(
      const GURL& intercepted_url,
      base::expected<net::structured_headers::Dictionary, std::string> result);
  void OnConnectionStatusHeaderParsed(
      const GURL& intercepted_url,
      base::expected<net::structured_headers::Dictionary, std::string> result);
  void OnTokenResponse(
      blink::mojom::RequestTokenStatus status,
      const std::optional<GURL>& selected_identity_provider_config_url,
      std::optional<base::Value> token,
      blink::mojom::TokenErrorPtr error,
      bool is_auto_selected);

  RequestInitiator request_initiator_;
  bool is_inside_onheaderparsed_ = false;
  bool should_cancel_ = false;
  // Tracks the document present in the target RenderFrameHost at the time the
  // relevant navigation began. This will be navigated to complete the FedCM
  // flow after the initiating navigation is canceled and replaced. A
  // WeakDocumentPtr is used so that the FedCM flow will not continue if the
  // target frame otherwise navigates in the meantime.
  WeakDocumentPtr document_;
  base::WeakPtrFactory<NavigationInterceptor> weak_ptr_factory_{this};
};

}  // namespace webid
}  // namespace content

#endif  // CONTENT_BROWSER_WEBID_NAVIGATION_INTERCEPTOR_H_
