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

#include "content/browser/webid/document_metadata.h"

#include <optional>

#include "content/public/browser/render_frame_host.h"
#include "services/service_manager/public/cpp/interface_provider.h"

namespace content::webid {

namespace {

constexpr char kLoginActionType[] = "LoginAction";
constexpr char kFederationProperty[] = "federation";
constexpr char kProvidersProperty[] = "providers";
constexpr char kConfigUrlProperty[] = "configURL";
constexpr char kClientIdProperty[] = "clientId";
constexpr char kNonceProperty[] = "nonce";
constexpr char kFieldsProperty[] = "fields";

schema_org::mojom::EntityPtr GetEntityProperty(
    const schema_org::mojom::Entity& entity,
    const std::string& name) {
  for (const auto& property : entity.properties) {
    if (property->name == name && property->values->is_entity_values() &&
        !property->values->get_entity_values().empty()) {
      return property->values->get_entity_values()[0].Clone();
    }
  }
  return nullptr;
}

std::optional<std::string> GetStringProperty(
    const schema_org::mojom::EntityPtr& entity,
    const std::string& name) {
  if (!entity) {
    return std::nullopt;
  }
  for (const auto& property : entity->properties) {
    if (property->name == name && property->values->is_string_values() &&
        !property->values->get_string_values().empty()) {
      return property->values->get_string_values()[0];
    }
  }
  return std::nullopt;
}

std::optional<std::vector<std::string>> GetStringArrayProperty(
    const schema_org::mojom::EntityPtr& entity,
    const std::string& name) {
  if (!entity) {
    return std::nullopt;
  }
  for (const auto& property : entity->properties) {
    if (property->name == name && property->values->is_string_values()) {
      return property->values->get_string_values();
    }
  }
  return std::nullopt;
}

std::optional<blink::mojom::IdentityProviderGetParametersPtr> Parse(
    const schema_org::mojom::Entity& entity) {
  if (entity.type != kLoginActionType) {
    return std::nullopt;
  }

  auto federation = GetEntityProperty(entity, kFederationProperty);
  if (!federation) {
    return std::nullopt;
  }

  auto params = blink::mojom::IdentityProviderGetParameters::New();
  params->context = blink::mojom::RpContext::kSignIn;
  params->mode = blink::mojom::RpMode::kPassive;

  for (const auto& property : federation->properties) {
    if (property->name == kProvidersProperty &&
        property->values->is_entity_values()) {
      for (const auto& provider_entity :
           property->values->get_entity_values()) {
        auto options = blink::mojom::IdentityProviderRequestOptions::New();
        options->config = blink::mojom::IdentityProviderConfig::New();

        // TODO(crbug.com/477699742): validate that the necessary fields
        // are present and well-formed.
        auto config_url =
            GetStringProperty(provider_entity, kConfigUrlProperty);
        if (config_url) {
          options->config->config_url = GURL(*config_url);
        }

        auto client_id = GetStringProperty(provider_entity, kClientIdProperty);
        if (client_id) {
          options->config->client_id = *client_id;
        }

        auto nonce = GetStringProperty(provider_entity, kNonceProperty);
        if (nonce) {
          options->nonce = *nonce;
        }

        options->fields =
            GetStringArrayProperty(provider_entity, kFieldsProperty);

        if (options->config->config_url.is_valid()) {
          params->providers.push_back(std::move(options));
        }
      }
    }
  }

  if (params->providers.empty()) {
    return std::nullopt;
  }

  return std::move(params);
}

}  // namespace

DocumentMetadata::DocumentMetadata(RenderFrameHost* rfh) {
  rfh->GetRemoteInterfaces()->GetInterface(
      metadata_remote_.BindNewPipeAndPassReceiver());
}

DocumentMetadata::~DocumentMetadata() = default;

void DocumentMetadata::GetLoginActions(LoginActionsCallback callback) {
  metadata_remote_->GetEntities(base::BindOnce(&DocumentMetadata::OnGetEntities,
                                               base::Unretained(this),
                                               std::move(callback)));
}

void DocumentMetadata::OnGetEntities(LoginActionsCallback callback,
                                     blink::mojom::WebPagePtr page) {
  std::vector<blink::mojom::IdentityProviderGetParametersPtr> actions;
  if (page) {
    for (const auto& entity : page->entities) {
      auto params = Parse(*entity);
      if (params) {
        actions.push_back(std::move(*params));
      }
    }
  }
  std::move(callback).Run(std::move(actions));
}

}  // namespace content::webid
