package com.airlock.iam.common.domain.model.geolocation;

import com.airlock.iam.common.api.domain.model.geolocation.Coordinates;
import com.airlock.iam.common.api.domain.model.geolocation.Geolocation;
import com.google.common.base.MoreObjects;
import edu.umd.cs.findbugs.annotations.SuppressFBWarnings;
import jakarta.annotation.Nullable;
import java.util.Optional;
import java.util.TimeZone;
import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

public class GeolocationImpl implements Geolocation {
   @Nullable
   private final String continentCode;
   @Nullable
   private final String countryCode;
   @Nullable
   private final String subdivisionCode;
   @Nullable
   private final String city;
   @Nullable
   private final String zip;
   @Nullable
   private final Coordinates coordinates;
   @Nullable
   private final String timeZoneId;

   @Override
   public Optional<Coordinates> getCoordinates() {
      return Optional.ofNullable(this.coordinates);
   }

   @Override
   public Optional<String> getContinentCode() {
      return Optional.ofNullable(this.continentCode);
   }

   @Override
   public Optional<String> getCountryCode() {
      return Optional.ofNullable(this.countryCode);
   }

   @Override
   public Optional<String> getSubdivisionCode() {
      return Optional.ofNullable(this.subdivisionCode);
   }

   @Override
   public Optional<String> getCity() {
      return Optional.ofNullable(this.city);
   }

   @Override
   public Optional<String> getZip() {
      return Optional.ofNullable(this.zip);
   }

   @Override
   public Optional<TimeZone> getTimeZone() {
      return this.timeZoneId == null ? Optional.empty() : Optional.of(TimeZone.getTimeZone(this.timeZoneId));
   }

   @Override
   public String toLogString() {
      return new ToStringBuilder(this, ToStringStyle.SHORT_PREFIX_STYLE)
         .append("continentCode", this.unknownIfNull(this.continentCode))
         .append("countryCode", this.unknownIfNull(this.countryCode))
         .append("subdivisionCode", this.unknownIfNull(this.subdivisionCode))
         .append("city", this.unknownIfNull(this.city))
         .append("zip", this.unknownIfNull(this.zip))
         .append("latitude", this.unknownIfNull(this.getCoordinates().map(Coordinates::getLatitude).map(Object::toString).orElse(null)))
         .append("longitude", this.unknownIfNull(this.getCoordinates().map(Coordinates::getLongitude).map(Object::toString).orElse(null)))
         .append("timezone", this.unknownIfNull(this.timeZoneId))
         .toString();
   }

   private String unknownIfNull(String value) {
      return (String)MoreObjects.firstNonNull(value, "<unknown>");
   }

   @SuppressFBWarnings(justification = "generated code")
   GeolocationImpl(
      @Nullable String continentCode,
      @Nullable String countryCode,
      @Nullable String subdivisionCode,
      @Nullable String city,
      @Nullable String zip,
      @Nullable Coordinates coordinates,
      @Nullable String timeZoneId
   ) {
      this.continentCode = continentCode;
      this.countryCode = countryCode;
      this.subdivisionCode = subdivisionCode;
      this.city = city;
      this.zip = zip;
      this.coordinates = coordinates;
      this.timeZoneId = timeZoneId;
   }

   @SuppressFBWarnings(justification = "generated code")
   public static GeolocationImpl.GeolocationImplBuilder builder() {
      return new GeolocationImpl.GeolocationImplBuilder();
   }

   @SuppressFBWarnings(justification = "generated code")
   @Override
   public String toString() {
      return "GeolocationImpl(continentCode="
         + this.continentCode
         + ", countryCode="
         + this.countryCode
         + ", subdivisionCode="
         + this.subdivisionCode
         + ", city="
         + this.city
         + ", zip="
         + this.zip
         + ", coordinates="
         + this.coordinates
         + ", timeZoneId="
         + this.timeZoneId
         + ")";
   }

   @SuppressFBWarnings(justification = "generated code")
   @Override
   public boolean equals(Object o) {
      if (o == this) {
         return true;
      } else if (!(o instanceof GeolocationImpl other)) {
         return false;
      } else {
         if (!other.canEqual(this)) {
            return false;
         }

         Object this$continentCode = this.continentCode;
         Object other$continentCode = other.continentCode;
         if (this$continentCode == null ? other$continentCode == null : this$continentCode.equals(other$continentCode)) {
            Object this$countryCode = this.countryCode;
            Object other$countryCode = other.countryCode;
            if (this$countryCode == null ? other$countryCode == null : this$countryCode.equals(other$countryCode)) {
               Object this$subdivisionCode = this.subdivisionCode;
               Object other$subdivisionCode = other.subdivisionCode;
               if (this$subdivisionCode == null ? other$subdivisionCode == null : this$subdivisionCode.equals(other$subdivisionCode)) {
                  Object this$city = this.city;
                  Object other$city = other.city;
                  if (this$city == null ? other$city == null : this$city.equals(other$city)) {
                     Object this$zip = this.zip;
                     Object other$zip = other.zip;
                     if (this$zip == null ? other$zip == null : this$zip.equals(other$zip)) {
                        Object this$coordinates = this.coordinates;
                        Object other$coordinates = other.coordinates;
                        if (this$coordinates == null ? other$coordinates == null : this$coordinates.equals(other$coordinates)) {
                           Object this$timeZoneId = this.timeZoneId;
                           Object other$timeZoneId = other.timeZoneId;
                           return this$timeZoneId == null ? other$timeZoneId == null : this$timeZoneId.equals(other$timeZoneId);
                        } else {
                           return false;
                        }
                     } else {
                        return false;
                     }
                  } else {
                     return false;
                  }
               } else {
                  return false;
               }
            } else {
               return false;
            }
         } else {
            return false;
         }
      }
   }

   @SuppressFBWarnings(justification = "generated code")
   protected boolean canEqual(Object other) {
      return other instanceof GeolocationImpl;
   }

   @SuppressFBWarnings(justification = "generated code")
   @Override
   public int hashCode() {
      int PRIME = 59;
      int result = 1;
      Object $continentCode = this.continentCode;
      result = result * 59 + ($continentCode == null ? 43 : $continentCode.hashCode());
      Object $countryCode = this.countryCode;
      result = result * 59 + ($countryCode == null ? 43 : $countryCode.hashCode());
      Object $subdivisionCode = this.subdivisionCode;
      result = result * 59 + ($subdivisionCode == null ? 43 : $subdivisionCode.hashCode());
      Object $city = this.city;
      result = result * 59 + ($city == null ? 43 : $city.hashCode());
      Object $zip = this.zip;
      result = result * 59 + ($zip == null ? 43 : $zip.hashCode());
      Object $coordinates = this.coordinates;
      result = result * 59 + ($coordinates == null ? 43 : $coordinates.hashCode());
      Object $timeZoneId = this.timeZoneId;
      return result * 59 + ($timeZoneId == null ? 43 : $timeZoneId.hashCode());
   }

   @SuppressFBWarnings(justification = "generated code")
   public static class GeolocationImplBuilder {
      @SuppressFBWarnings(justification = "generated code")
      private String continentCode;
      @SuppressFBWarnings(justification = "generated code")
      private String countryCode;
      @SuppressFBWarnings(justification = "generated code")
      private String subdivisionCode;
      @SuppressFBWarnings(justification = "generated code")
      private String city;
      @SuppressFBWarnings(justification = "generated code")
      private String zip;
      @SuppressFBWarnings(justification = "generated code")
      private Coordinates coordinates;
      @SuppressFBWarnings(justification = "generated code")
      private String timeZoneId;

      @SuppressFBWarnings(justification = "generated code")
      GeolocationImplBuilder() {
      }

      @SuppressFBWarnings(justification = "generated code")
      public GeolocationImpl.GeolocationImplBuilder continentCode(@Nullable String continentCode) {
         this.continentCode = continentCode;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GeolocationImpl.GeolocationImplBuilder countryCode(@Nullable String countryCode) {
         this.countryCode = countryCode;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GeolocationImpl.GeolocationImplBuilder subdivisionCode(@Nullable String subdivisionCode) {
         this.subdivisionCode = subdivisionCode;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GeolocationImpl.GeolocationImplBuilder city(@Nullable String city) {
         this.city = city;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GeolocationImpl.GeolocationImplBuilder zip(@Nullable String zip) {
         this.zip = zip;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GeolocationImpl.GeolocationImplBuilder coordinates(@Nullable Coordinates coordinates) {
         this.coordinates = coordinates;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GeolocationImpl.GeolocationImplBuilder timeZoneId(@Nullable String timeZoneId) {
         this.timeZoneId = timeZoneId;
         return this;
      }

      @SuppressFBWarnings(justification = "generated code")
      public GeolocationImpl build() {
         return new GeolocationImpl(this.continentCode, this.countryCode, this.subdivisionCode, this.city, this.zip, this.coordinates, this.timeZoneId);
      }

      @SuppressFBWarnings(justification = "generated code")
      @Override
      public String toString() {
         return "GeolocationImpl.GeolocationImplBuilder(continentCode="
            + this.continentCode
            + ", countryCode="
            + this.countryCode
            + ", subdivisionCode="
            + this.subdivisionCode
            + ", city="
            + this.city
            + ", zip="
            + this.zip
            + ", coordinates="
            + this.coordinates
            + ", timeZoneId="
            + this.timeZoneId
            + ")";
      }
   }
}
