package com.hubspot.baragon.models;

import com.fasterxml.jackson.annotation.JsonIgnore;
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.annotation.JsonProperty;
import com.google.common.base.Objects;
import com.google.common.base.Strings;
import io.dropwizard.validation.ValidationMethod;
import org.hibernate.validator.constraints.NotEmpty;

import javax.validation.constraints.NotNull;
import javax.validation.constraints.Pattern;
import java.util.Collection;
import java.util.List;
import java.util.Map;

@JsonIgnoreProperties(ignoreUnknown = true)
public class Service {
  @NotEmpty
  @Pattern(regexp = "[^\\s/|]+", message = "cannot contain whitespace, '/', or '|'", flags = Pattern.Flag.MULTILINE)
  private final String serviceId;

  @NotNull
  private final Collection<String> owners;

  @NotEmpty
  @Pattern(regexp = "/(?:[A-Za-z0-9\\-._~!$&'()*+,;=:@/?]|%[0-9A-Fa-f]{2})*", message = "must be an absolute URL path")
  private final String serviceBasePath;

  @NotEmpty
  private final List<String> loadBalancerGroups;

  private final Map<String, Object> options;
  
  public Service(@JsonProperty("serviceId") String serviceId,
                 @JsonProperty("owners") Collection<String> owners,
                 @JsonProperty("serviceBasePath") String serviceBasePath,
                 @JsonProperty("loadBalancerBaseUri") String loadBalancerBaseUri,  // <-- this is going away soon
                 @JsonProperty("loadBalancerGroups") List<String> loadBalancerGroups,
                 @JsonProperty("options") Map<String, Object> options) {
    this.serviceId = serviceId;
    this.owners = owners;
    this.serviceBasePath = !Strings.isNullOrEmpty(serviceBasePath) ? serviceBasePath : loadBalancerBaseUri;
    this.loadBalancerGroups = loadBalancerGroups;
    this.options = options;

    // TODO: bring back rewriteAppRootTo (sorry Ian)
  }

  public String getServiceId() {
    return serviceId;
  }

  public Collection<String> getOwners() {
    return owners;
  }

  public String getServiceBasePath() {
    return serviceBasePath;
  }

  @JsonIgnore
  @Deprecated
  public String getLoadBalancerBaseUri() {
    return serviceBasePath;
  }

  public List<String> getLoadBalancerGroups() {
    return loadBalancerGroups;
  }

  public Map<String, Object> getOptions() {
    return options;
  }

  @ValidationMethod(message = "loadBalancerGroups cannot contain '/'")
  public boolean validLoadBalancerGroups() {
    if (loadBalancerGroups != null) {
      for (String loadBalancerGroup : loadBalancerGroups) {
        if (loadBalancerGroup.contains("/")) {
          return false;
        }
      }
    }

    return true;
  }

  @Override
  public String toString() {
    return Objects.toStringHelper(Service.class)
        .add("serviceId", serviceId)
        .add("owners", owners)
        .add("serviceBasePath", serviceBasePath)
        .add("loadBalancerGroups", loadBalancerGroups)
        .add("options", options)
        .toString();
  }

  @Override
  public int hashCode() {
    return Objects.hashCode(serviceId, owners, serviceBasePath, loadBalancerGroups, options);
  }

  @Override
  public boolean equals(Object that) {
    if (this == that) {
      return true;
    }

    if (that == null) {
      return false;
    }

    if (that instanceof Service) {
      return Objects.equal(serviceId, ((Service)that).getServiceId())
          && Objects.equal(owners, ((Service)that).getOwners())
          && Objects.equal(serviceBasePath, ((Service)that).getServiceBasePath())
          && Objects.equal(loadBalancerGroups, ((Service)that).getLoadBalancerGroups())
          && Objects.equal(options, ((Service)that).getOptions());
    }

    return false;
  }
}

@@ -3182,20 +3182,17 @@
 (Object 
-that
+o
 ) %7B%0A    
@@ -3207,21 +3207,10 @@
  == 
-that) %7B%0A     
+o)
  ret
@@ -3219,31 +3219,24 @@
 n true;%0A
-    %7D%0A%0A
     if (
 that == 
@@ -3231,20 +3231,17 @@
 if (
-that
+o
  == null
 ) %7B%0A
@@ -3240,63 +3240,78 @@
 null
-) %7B%0A      return false;%0A    %7D%0A%0A    if (that instanceof 
+ %7C%7C getClass() != o.getClass()) return false;%0A%0A    Service service = (
 Serv
@@ -3319,44 +3319,54 @@
 ce) 
-%7B
+o;%0A
 %0A    
-  return Object
+if (!loadBalancerGroup
 s.equal
+s
 (service
 Id, 
@@ -3365,142 +3365,174 @@
 vice
-Id, ((Service)that).getServiceId())%0A          && Objects.equal(owners, ((Service)that).getOwners())%0A          && Object
+.loadBalancerGroups)) return false;%0A    if (options != null ? !options.equals(service.options) : service.options != null) return false;%0A    if (!owner
 s.equal
+s
 (service
 Base
@@ -3531,216 +3531,163 @@
 vice
-BasePath, ((Service)that).getServiceBasePath())%0A          && Objects.equal(loadBalancerGroups, ((Service)that).getLoadBalancerGroups())%0A          && Objects.equal(options, ((Service)that).getOptions());%0A    %7D
+.owners)) return false;%0A    if (!serviceBasePath.equals(service.serviceBasePath)) return false;%0A    if (!serviceId.equals(service.serviceId)) return false;
 %0A%0A  
@@ -3691,25 +3691,24 @@
 %0A    return 
-fals
+tru
 e;%0A  %7D%0A%7D%0A

tweak Service.equals()