/*
 * Copyright 2014 Netflix, Inc.
 *
 * 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.netflix.spinnaker.clouddriver.aws.deploy.validators;

import com.netflix.spinnaker.clouddriver.aws.AmazonOperation;
import com.netflix.spinnaker.clouddriver.aws.deploy.description.UpsertAmazonLoadBalancerClassicDescription;
import com.netflix.spinnaker.clouddriver.aws.deploy.description.UpsertAmazonLoadBalancerV2Description;
import com.netflix.spinnaker.clouddriver.aws.security.AmazonCredentials;
import com.netflix.spinnaker.clouddriver.orchestration.AtomicOperations;
import com.netflix.spinnaker.clouddriver.aws.deploy.description.UpsertAmazonLoadBalancerDescription;
import org.springframework.stereotype.Component;
import org.springframework.validation.Errors;

import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

@AmazonOperation(AtomicOperations.UPSERT_LOAD_BALANCER)
@Component("createAmazonLoadBalancerDescriptionValidator")
class CreateAmazonLoadBalancerDescriptionValidator extends AmazonDescriptionValidationSupport<UpsertAmazonLoadBalancerDescription> {

  @Override
  public void validate(List priorDescriptions, UpsertAmazonLoadBalancerDescription description, Errors errors) {
    // Common fields to validate
    if (description.getName() == null && description.getClusterName() == null) {
      errors.rejectValue("clusterName", "createAmazonLoadBalancerDescription.missing.name.or.clusterName");
    }
    if (description.getSubnetType() == null && description.getAvailabilityZones() == null) {
      errors.rejectValue("availabilityZones", "createAmazonLoadBalancerDescription.missing.subnetType.or.availabilityZones");
    }

    if (description.getAvailabilityZones() != null) {
      for (Map.Entry<String, List<String>> entry : description.getAvailabilityZones().entrySet()) {
        String region = entry.getKey();
        List<String> azs = entry.getValue();

        AmazonCredentials.AWSRegion acctRegion = description.getCredentials().getRegions().stream().filter(r -> r.getName().equals(region)).findFirst().orElse(null);
        if (acctRegion == null) {
          errors.rejectValue("availabilityZones", "createAmazonLoadBalancerDescription.region.not.configured");
        }
        if (description.getSubnetType() == null && azs == null) {
          errors.rejectValue("availabilityZones", "createAmazonLoadBalancerDescription.missing.subnetType.or.availabilityZones");
          break;
        }
        if (description.getSubnetType() == null && acctRegion != null && !acctRegion.getAvailabilityZones().containsAll(azs)) {
          errors.rejectValue("availabilityZones", "createAmazonLoadBalancerDescription.zone.not.configured");
        }
      }
    }

    switch (description.getLoadBalancerType()) {
      case CLASSIC:
        UpsertAmazonLoadBalancerClassicDescription classicDescription = (UpsertAmazonLoadBalancerClassicDescription) description;
        if (classicDescription.getListeners() == null || classicDescription.getListeners().size() == 0) {
          errors.rejectValue("listeners", "createAmazonLoadBalancerDescription.listeners.empty");
        }
        break;
      case APPLICATION:
        UpsertAmazonLoadBalancerV2Description albDescription = (UpsertAmazonLoadBalancerV2Description) description;
        if (albDescription.targetGroups == null || albDescription.targetGroups.size() == 0) {
          errors.rejectValue("targetGroups", "createAmazonLoadBalancerDescription.targetGroups.empty");
        }

        Set<String> unusedTargetGroupNames = new HashSet<>();
        for (UpsertAmazonLoadBalancerV2Description.TargetGroup targetGroup : albDescription.targetGroups) {
          unusedTargetGroupNames.add(targetGroup.getName());
          if (targetGroup.getName() == null || targetGroup.getName().isEmpty()) {
            errors.rejectValue("targetGroups", "createAmazonLoadBalancerDescription.targetGroups.name.missing");
          }
          if (targetGroup.getProtocol() == null) {
            errors.rejectValue("targetGroups", "createAmazonLoadBalancerDescription.targetGroups.protocol.missing");
          }
          if (targetGroup.getPort() == null) {
            errors.rejectValue("targetGroups", "createAmazonLoadBalancerDescription.targetGroups.port.missing");
          }
        }
        for (UpsertAmazonLoadBalancerV2Description.Listener listener : albDescription.listeners) {
          if (listener.getDefaultActions().size() == 0) {
            errors.rejectValue("listeners", "createAmazonLoadBalancerDescription.listeners.missing.defaultAction");
          }
          for (UpsertAmazonLoadBalancerV2Description.Action action : listener.getDefaultActions()) {
            unusedTargetGroupNames.remove(action.getTargetGroupName());
          }
          for (UpsertAmazonLoadBalancerV2Description.Rule rule : listener.getRules()) {
            for (UpsertAmazonLoadBalancerV2Description.Action action : rule.getActions()) {
              String targetGroupName = action.getTargetGroupName();
              if (!unusedTargetGroupNames.contains(targetGroupName)) {
                errors.rejectValue("listeners", "createAmazonLoadBalancerDescription.listeners.invalid.targetGroup");
              }
              unusedTargetGroupNames.remove(action.getTargetGroupName());
            }
          }
          if (unusedTargetGroupNames.size() > 0) {
            errors.rejectValue("targetGroups", "createAmazonLoadBalancerDescription.targetGroups.unused");
          }
        }
        break;
      default:
          errors.rejectValue("loadBalancerType", "createAmazonLoadBalancerDescription.loadBalancerType.invalid");
        break;
    }
  }
}

@@ -5108,193 +5108,8 @@
   %7D%0A
-          for (UpsertAmazonLoadBalancerV2Description.Action action : listener.getDefaultActions()) %7B%0A            unusedTargetGroupNames.remove(action.getTargetGroupName());%0A          %7D%0A
     
@@ -5651,32 +5651,40 @@
 %7D%0A          %7D%0A  
+      %7D%0A
         if (unus
@@ -5712,26 +5712,24 @@
 ze() %3E 0) %7B%0A
-  
           er
@@ -5817,36 +5817,24 @@
 s.unused%22);%0A
-          %7D%0A
         %7D%0A  

Fix create alb for real (#1709)