// Copyright 2017 The Nomulus Authors. All Rights Reserved.
//
// 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 google.registry.testing;

import static google.registry.testing.DatabaseHelper.generateNewDomainRoid;
import static google.registry.testing.DatabaseHelper.generateNewHostRoid;
import static google.registry.testing.DatabaseHelper.persistResource;
import static google.registry.util.DomainNameUtils.getTldFromDomainName;
import static java.nio.charset.StandardCharsets.UTF_8;

import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.net.InetAddresses;
import google.registry.model.EppResource;
import google.registry.model.domain.Domain;
import google.registry.model.domain.DomainHistory;
import google.registry.model.domain.Period;
import google.registry.model.domain.secdns.DomainDsData;
import google.registry.model.eppcommon.StatusValue;
import google.registry.model.eppcommon.Trid;
import google.registry.model.host.Host;
import google.registry.model.registrar.Registrar;
import google.registry.model.registrar.RegistrarAddress;
import google.registry.model.registrar.RegistrarPoc;
import google.registry.model.reporting.HistoryEntry;
import google.registry.persistence.VKey;
import google.registry.util.Idn;
import java.net.InetAddress;
import java.time.Instant;
import javax.annotation.Nullable;

/** Test helper methods for the RDAP package. */
public final class FullFieldsTestEntityHelper {

  public static Registrar makeRegistrar(
      String registrarId, String registrarName, Registrar.State state) {
    return makeRegistrar(registrarId, registrarName, state, 1L);
  }

  public static Registrar makeRegistrar(
      String registrarId, String registrarName, Registrar.State state, Long ianaIdentifier) {
    return new Registrar.Builder()
        .setRegistrarId(registrarId)
        .setRegistrarName(registrarName)
        .setType(Registrar.Type.REAL)
        .setIanaIdentifier(ianaIdentifier)
        .setState(state)
        .setInternationalizedAddress(
            new RegistrarAddress.Builder()
                .setStreet(ImmutableList.of("123 Example Boulevard <script>"))
                .setCity("Williamsburg <script>")
                .setState("NY")
                .setZip("11211")
                .setCountryCode("US")
                .build())
        .setLocalizedAddress(
            new RegistrarAddress.Builder()
                .setStreet(ImmutableList.of("123 Example Boulevard <script>"))
                .setCity("Williamsburg <script>")
                .setState("NY")
                .setZip("11211")
                .setCountryCode("US")
                .build())
        .setPhoneNumber("+1.2125551212")
        .setFaxNumber("+1.2125551213")
        .setEmailAddress("contact-us@example.com")
        .setWhoisServer("whois.example.com")
        .setRdapBaseUrls(ImmutableSet.of("https://rdap.example.com/withSlash/"))
        .setUrl("http://my.fake.url")
        .build();
  }

  public static ImmutableList<RegistrarPoc> makeRegistrarPocs(Registrar registrar) {
    return ImmutableList.of(
        new RegistrarPoc.Builder()
            .setRegistrar(registrar)
            .setName("John Doe")
            .setEmailAddress("johndoe@example.com")
            .setPhoneNumber("+1.2125551213")
            .setFaxNumber("+1.2125551213")
            .setTypes(ImmutableSet.of(RegistrarPoc.Type.ADMIN))
            // Purposely flip the internal/external admin/tech
            // distinction to make sure we're not relying on it.  Sigh.
            .setVisibleInRdapAsAdmin(false)
            .setVisibleInRdapAsTech(true)
            .build(),
        new RegistrarPoc.Builder()
            .setRegistrar(registrar)
            .setName("Jane Doe")
            .setEmailAddress("janedoe@example.com")
            .setPhoneNumber("+1.2125551215")
            .setFaxNumber("+1.2125551216")
            .setTypes(ImmutableSet.of(RegistrarPoc.Type.TECH))
            // Purposely flip the internal/external admin/tech
            // distinction to make sure we're not relying on it.  Sigh.
            .setVisibleInRdapAsAdmin(true)
            .setVisibleInRdapAsTech(false)
            .build(),
        new RegistrarPoc.Builder()
            .setRegistrar(registrar)
            .setName("Jake Doe")
            .setEmailAddress("jakedoe@example.com")
            .setPhoneNumber("+1.2125551216")
            .setFaxNumber("+1.2125551216")
            .setVisibleInDomainRdapAsAbuse(true)
            .build());
  }

  public static Host makeHost(String fqhn, String ip) {
    return makeHost(fqhn, ip, null);
  }

  public static Host makeHost(String fqhn, @Nullable String ip1, @Nullable String ip2) {
    return makeHost(fqhn, ip1, ip2, "TheRegistrar");
  }

  public static Host makeHost(
      String fqhn, @Nullable String ip1, @Nullable String ip2, String registrarClientId) {
    return makePunycodedHost(Idn.toASCII(fqhn), ip1, ip2, registrarClientId);
  }

  public static Host makePunycodedHost(
      String fqhn, @Nullable String ip1, @Nullable String ip2, String registrarClientId) {
    Host.Builder builder =
        new Host.Builder()
            .setRepoId(generateNewHostRoid())
            .setHostName(fqhn)
            .setCreationTimeForTest(Instant.parse("2000-10-08T00:45:00Z"))
            .setPersistedCurrentSponsorRegistrarId(registrarClientId);
    if ((ip1 != null) || (ip2 != null)) {
      ImmutableSet.Builder<InetAddress> ipBuilder = new ImmutableSet.Builder<>();
      if (ip1 != null) {
        ipBuilder.add(InetAddresses.forString(ip1));
      }
      if (ip2 != null) {
        ipBuilder.add(InetAddresses.forString(ip2));
      }
      builder.setInetAddresses(ipBuilder.build());
    }
    return builder.build();
  }

  public static Host makeAndPersistHost(
      String fqhn, @Nullable String ip, @Nullable Instant creationTime) {
    return makeAndPersistHost(fqhn, ip, null, creationTime);
  }

  public static Host makeAndPersistHost(
      String fqhn, @Nullable String ip1, @Nullable String ip2, @Nullable Instant creationTime) {
    return makeAndPersistHost(fqhn, ip1, ip2, creationTime, "TheRegistrar");
  }

  public static Host makeAndPersistHost(
      String fqhn,
      @Nullable String ip1,
      @Nullable String ip2,
      @Nullable Instant creationTime,
      String registrarClientId) {
    Host host = persistResource(makeHost(fqhn, ip1, ip2, registrarClientId));
    if (creationTime != null) {
      persistResource(
          makeHistoryEntry(host, HistoryEntry.Type.HOST_CREATE, null, "created", creationTime));
    }
    return host;
  }

  public static Domain makeDomain(
      String domain,
      @Nullable Host ns1,
      @Nullable Host ns2,
      Registrar registrar) {
    Domain.Builder builder =
        new Domain.Builder()
            .setDomainName(Idn.toASCII(domain))
            .setRepoId(generateNewDomainRoid(getTldFromDomainName(Idn.toASCII(domain))))
            .setLastEppUpdateTime(Instant.parse("2009-05-29T20:13:00Z"))
            .setCreationTimeForTest(Instant.parse("2000-10-08T00:45:00Z"))
            .setRegistrationExpirationTime(Instant.parse("2110-10-08T00:44:59Z"))
            .setPersistedCurrentSponsorRegistrarId(registrar.getRegistrarId())
            .setCreationRegistrarId(registrar.getRegistrarId())
            .setStatusValues(
                ImmutableSet.of(
                    StatusValue.CLIENT_DELETE_PROHIBITED,
                    StatusValue.CLIENT_RENEW_PROHIBITED,
                    StatusValue.CLIENT_TRANSFER_PROHIBITED,
                    StatusValue.SERVER_UPDATE_PROHIBITED))
            .setDsData(ImmutableSet.of(DomainDsData.create(1, 2, 3, "deadface")));
    if ((ns1 != null) || (ns2 != null)) {
      ImmutableSet.Builder<VKey<Host>> nsBuilder = new ImmutableSet.Builder<>();
      if (ns1 != null) {
        nsBuilder.add(ns1.createVKey());
      }
      if (ns2 != null) {
        nsBuilder.add(ns2.createVKey());
      }
      builder.setNameservers(nsBuilder.build());
    }
    return builder.build();
  }

  public static HistoryEntry makeHistoryEntry(
      EppResource resource,
      HistoryEntry.Type type,
      Period period,
      String reason,
      Instant modificationTime) {
    HistoryEntry.Builder<?, ?> builder =
        HistoryEntry.createBuilderForResource(resource)
            .setType(type)
            .setXmlBytes("<xml></xml>".getBytes(UTF_8))
            .setModificationTime(modificationTime)
            .setRegistrarId(resource.getPersistedCurrentSponsorRegistrarId())
            .setTrid(Trid.create("ABC-123", "server-trid"))
            .setBySuperuser(false)
            .setReason(reason)
            .setRequestedByRegistrar(false);
    if (builder instanceof DomainHistory.Builder domainHistoryBuilder) {
      domainHistoryBuilder.setPeriod(period);
    }
    return builder.build();
  }
}
