// Copyright (C) 2023 The Android Open Source Project
//
// 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
//
// http://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.

package com.googlesource.gerrit.plugins.spannerrefdb;

import com.google.cloud.NoCredentials;
import com.google.cloud.spanner.Database;
import com.google.cloud.spanner.DatabaseClient;
import com.google.cloud.spanner.DatabaseId;
import com.google.cloud.spanner.Instance;
import com.google.cloud.spanner.InstanceAdminClient;
import com.google.cloud.spanner.InstanceConfigId;
import com.google.cloud.spanner.InstanceId;
import com.google.cloud.spanner.InstanceInfo;
import com.google.cloud.spanner.Spanner;
import com.google.cloud.spanner.SpannerOptions;
import java.util.Collections;
import java.util.concurrent.ExecutionException;
import org.junit.Ignore;
import org.testcontainers.containers.SpannerEmulatorContainer;
import org.testcontainers.utility.DockerImageName;

@Ignore
public class EmulatedSpannerRefDb {
  public static final String PROJECT_ID = "test";
  public static final String SPANNER_INSTANCE_ID = "spanner-instance";
  public static final String SPANNER_DATABASE_ID = "global-refdb";

  private final SpannerEmulatorContainer container;

  private final Spanner spanner;
  private final SpannerOptions spannerOptions;
  private final InstanceAdminClient instanceAdminClient;
  private final Instance spannerInstance;
  private final Database spannerDatabase;
  private final DatabaseId dbId;
  private final DatabaseClient databaseClient;
  private final SpannerRefDatabase spannerRefDb;

  public EmulatedSpannerRefDb() throws Exception {
    container =
        new SpannerEmulatorContainer(
            DockerImageName.parse("gcr.io/cloud-spanner-emulator/emulator").withTag("1.5.9"));
    container.start();
    System.out.println(
        String.format(
            "Spanner emulator container started and is listening on %s",
            container.getEmulatorGrpcEndpoint()));

    spannerOptions = getEmulatorOptions();
    spanner = spannerOptions.getService();
    instanceAdminClient = spanner.getInstanceAdminClient();
    spannerInstance = createSpannerInstance();
    dbId = DatabaseId.of(spannerOptions.getProjectId(), SPANNER_INSTANCE_ID, SPANNER_DATABASE_ID);
    spannerDatabase =
        spannerInstance.createDatabase(SPANNER_DATABASE_ID, Collections.emptyList()).get();
    createSchema();
    databaseClient = createDatabaseClient();
    Lock.LockFactory lockFactory =
        new Lock.LockFactory() {
          @Override
          public Lock create(String projectName, String refName) {
            return new Lock(databaseClient, "", projectName, refName);
          }
        };
    spannerRefDb = new SpannerRefDatabase(databaseClient, lockFactory);
  }

  private void createSchema() {
    SpannerLifeCycleManager lcm = new SpannerLifeCycleManager(spannerOptions, dbId);
    lcm.start();
  }

  public void cleanup() {
    spannerDatabase.drop();
    instanceAdminClient.deleteInstance(SPANNER_INSTANCE_ID);
    spanner.close();
    container.stop();
    container.close();
    System.out.println("Spanner emulator container was stopped");
  }

  public SpannerEmulatorContainer getContainer() {
    return container;
  }

  public Database getSpannerDatabase() {
    return spannerDatabase;
  }

  public SpannerRefDatabase getSpannerRefDatabase() {
    return spannerRefDb;
  }

  private SpannerOptions getEmulatorOptions() {
    return SpannerOptions.newBuilder()
        .setEmulatorHost(container.getEmulatorGrpcEndpoint())
        .setCredentials(NoCredentials.getInstance())
        .setProjectId(PROJECT_ID)
        .build();
  }

  private Instance createSpannerInstance() throws InterruptedException, ExecutionException {
    InstanceConfigId instanceConfig = InstanceConfigId.of(PROJECT_ID, "emulator-config");
    InstanceId instanceId = InstanceId.of(PROJECT_ID, SPANNER_INSTANCE_ID);
    InstanceInfo instanceInfo =
        InstanceInfo.newBuilder(instanceId)
            .setInstanceConfigId(instanceConfig)
            .setNodeCount(1)
            .setDisplayName("test instance")
            .build();
    return instanceAdminClient.createInstance(instanceInfo).get();
  }

  private DatabaseClient createDatabaseClient() {
    return spannerOptions.getService().getDatabaseClient(dbId);
  }
}
