// Copyright 2026 Google LLC
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//    https://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//

#include "generator/generator_factory.h"

#include <memory>
#include <string>
#include <utility>

#include "absl/functional/any_invocable.h"
#include "absl/status/status.h"
#include "absl/status/status_matchers.h"
#include "absl/strings/string_view.h"
#include "absl/synchronization/notification.h"
#include "async/async_context.h"
#include "claim/generator.h"
#include "claim/manifest_box.h"
#include "claim/manifest_box_assembler.h"
#include "claim/signer.h"
#include "crypto/hash.h"
#include "generator/generator.h"
#include "generator/generator_options.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"
#include "proto/generator.pb.h"
#include "proto/generator_info.pb.h"

namespace credentio {
namespace {

using ::absl_testing::StatusIs;
using ::testing::HasSubstr;
using ::testing::NotNull;

class FakeClaimSigner : public ClaimSigner {
 public:
  void Sign(absl::string_view claim, Options options,
            absl::AnyInvocable<void(absl::StatusOr<SignResult>) &&> cb)
      const override {
    std::move(cb)(SignResult{.signature = "fake_sig"});
  }
};

class TrackingManifestBoxAssembler : public ManifestBoxAssembler {
 public:
  explicit TrackingManifestBoxAssembler(std::string name, int* call_count)
      : name_(std::move(name)), call_count_(call_count) {}

  absl::StatusOr<ManifestBox> Assemble(
      const GenerateManifestStoreRequest& request) const override {
    (*call_count_)++;
    return absl::InternalError(name_);
  }

 private:
  std::string name_;
  int* call_count_;
};

TEST(GeneratorFactoryTest, ValidateOptionsRejectsNullSigningClaimSigner) {
  FakeClaimSigner template_signer;
  GeneratorOptions options;
  options.signing_claim_signer = nullptr;
  options.template_claim_signer = &template_signer;

  EXPECT_THAT(CreateGenerator(std::move(options)),
              StatusIs(absl::StatusCode::kInvalidArgument,
                       HasSubstr("signing_claim_signer is required")));
}

TEST(GeneratorFactoryTest, ValidateOptionsRejectsNullTemplateClaimSigner) {
  FakeClaimSigner signing_signer;
  GeneratorOptions options;
  options.signing_claim_signer = &signing_signer;
  options.template_claim_signer = nullptr;

  EXPECT_THAT(CreateGenerator(std::move(options)),
              StatusIs(absl::StatusCode::kInvalidArgument,
                       HasSubstr("template_claim_signer is required")));
}

TEST(GeneratorFactoryTest, ValidateOptionsRejectsNullUuidGenerator) {
  FakeClaimSigner signing_signer;
  FakeClaimSigner template_signer;
  GeneratorOptions options;
  options.signing_claim_signer = &signing_signer;
  options.template_claim_signer = &template_signer;
  options.uuid_generator = nullptr;

  EXPECT_THAT(CreateGenerator(std::move(options)),
              StatusIs(absl::StatusCode::kInvalidArgument,
                       HasSubstr("uuid_generator is required")));
}

TEST(GeneratorFactoryTest, ValidateOptionsRejectsNullHashFactory) {
  FakeClaimSigner signing_signer;
  FakeClaimSigner template_signer;
  GeneratorOptions options;
  options.signing_claim_signer = &signing_signer;
  options.template_claim_signer = &template_signer;
  options.hash_factory = nullptr;

  EXPECT_THAT(CreateGenerator(std::move(options)),
              StatusIs(absl::StatusCode::kInvalidArgument,
                       HasSubstr("hash_factory is required")));
}

TEST(GeneratorFactoryTest, ValidateOptionsRejectsNullManifestAssemblerFactory) {
  FakeClaimSigner signing_signer;
  FakeClaimSigner template_signer;
  GeneratorOptions options;
  options.signing_claim_signer = &signing_signer;
  options.template_claim_signer = &template_signer;
  options.manifest_assembler_factory = nullptr;

  EXPECT_THAT(CreateGenerator(std::move(options)),
              StatusIs(absl::StatusCode::kInvalidArgument,
                       HasSubstr("manifest_assembler_factory is required")));
}

TEST(GeneratorFactoryTest, CreateGeneratorSuccess) {
  FakeClaimSigner signing_signer;
  FakeClaimSigner template_signer;
  GeneratorOptions options;
  options.generator_info.set_name("TestGenerator");
  options.generator_info.set_spec_version("2.2.0");
  options.signing_claim_signer = &signing_signer;
  options.template_claim_signer = &template_signer;

  auto generator_or = CreateGenerator(std::move(options));
  ABSL_ASSERT_OK(generator_or);
  EXPECT_THAT(*generator_or, NotNull());
}

TEST(GeneratorFactoryTest, DualModeGeneratorDelegation) {
  FakeClaimSigner signing_signer;
  FakeClaimSigner template_signer;
  int signing_assemble_count = 0;
  int template_assemble_count = 0;

  GeneratorOptions options;
  options.generator_info.set_name("TestGenerator");
  options.generator_info.set_spec_version("2.2.0");
  options.signing_claim_signer = &signing_signer;
  options.template_claim_signer = &template_signer;
  options.manifest_assembler_factory =
      [&](const CreateManifestAssemblerOptions& opts)
      -> absl::StatusOr<std::unique_ptr<ManifestBoxAssembler>> {
    if (dynamic_cast<const TemplatedHasherFactory*>(opts.hash_factory) !=
        nullptr) {
      return std::make_unique<TrackingManifestBoxAssembler>(
          "template_assembler", &template_assemble_count);
    }
    return std::make_unique<TrackingManifestBoxAssembler>(
        "signing_assembler", &signing_assemble_count);
  };

  auto generator_or = CreateGenerator(std::move(options));
  ABSL_ASSERT_OK(generator_or);
  auto generator = std::move(*generator_or);

  // GenerateManifestStore should delegate to the signing generator.
  GenerateManifestStoreRequest gen_request;
  absl::Notification gen_done;
  absl::Status gen_status;
  generator->GenerateManifestStore(
      gen_request, AsyncContext(),
      [&](absl::StatusOr<GenerateManifestStoreResponse> res) {
        gen_status = res.status();
        gen_done.Notify();
      });
  gen_done.WaitForNotification();
  EXPECT_THAT(gen_status, StatusIs(absl::StatusCode::kInternal,
                                   HasSubstr("signing_assembler")));
  EXPECT_EQ(signing_assemble_count, 1);
  EXPECT_EQ(template_assemble_count, 0);

  // GenerateManifestStoreTemplate should delegate to the template generator.
  absl::Notification template_done;
  absl::Status template_status;
  generator->GenerateManifestStoreTemplate(
      gen_request, AsyncContext(),
      [&](absl::StatusOr<ManifestStoreTemplate> res) {
        template_status = res.status();
        template_done.Notify();
      });
  template_done.WaitForNotification();
  EXPECT_THAT(template_status, StatusIs(absl::StatusCode::kInternal,
                                        HasSubstr("template_assembler")));
  EXPECT_EQ(signing_assemble_count, 1);
  EXPECT_EQ(template_assemble_count, 1);

  // FinalizeManifestStore should delegate to the signing generator.
  FinalizeManifestStoreRequest fin_request;
  absl::Notification fin_done;
  absl::Status fin_status;
  generator->FinalizeManifestStore(
      fin_request, AsyncContext(),
      [&](absl::StatusOr<FinalizeManifestStoreResponse> res) {
        fin_status = res.status();
        fin_done.Notify();
      });
  fin_done.WaitForNotification();
  EXPECT_THAT(fin_status, StatusIs(absl::StatusCode::kInvalidArgument,
                                   HasSubstr("generator_context")));
}

}  // namespace
}  // namespace credentio
