/*
 *  Copyright 2019 Pivotal, 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.orca.clouddriver.tasks.providers.cf;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.google.common.collect.ImmutableMap;
import com.netflix.spinnaker.kork.artifacts.model.Artifact;
import com.netflix.spinnaker.orca.clouddriver.tasks.manifest.ManifestContext;
import com.netflix.spinnaker.orca.clouddriver.tasks.manifest.ManifestEvaluator;
import com.netflix.spinnaker.orca.clouddriver.tasks.servergroup.ServerGroupCreator;
import com.netflix.spinnaker.orca.pipeline.model.Execution;
import com.netflix.spinnaker.orca.pipeline.model.Stage;
import com.netflix.spinnaker.orca.pipeline.util.ArtifactUtils;
import java.util.Collections;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import javax.annotation.Nullable;
import lombok.Data;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

@Slf4j
@Component
@RequiredArgsConstructor
class CloudFoundryServerGroupCreator implements ServerGroupCreator {
  private final ObjectMapper mapper;
  private final ArtifactUtils artifactUtils;
  private final ManifestEvaluator manifestEvaluator;

  @Override
  public List<Map> getOperations(Stage stage) {
    Map<String, Object> context = stage.getContext();

    DeploymentManifest manifest =
        mapper.convertValue(context.get("manifest"), DeploymentManifest.class);
    CloudFoundryManifestContext manifestContext =
        CloudFoundryManifestContext.builder()
            .source(ManifestContext.Source.Artifact)
            .manifestArtifactId(manifest.getArtifactId())
            .manifestArtifact(manifest.getArtifact())
            .manifestArtifactAccount(manifest.getArtifact().getArtifactAccount())
            .skipExpressionEvaluation(
                (Boolean)
                    Optional.ofNullable(context.get("skipExpressionEvaluation")).orElse(false))
            .build();
    ManifestEvaluator.Result manifestResult = manifestEvaluator.evaluate(stage, manifestContext);
    final Execution execution = stage.getExecution();
    ImmutableMap.Builder<String, Object> operation =
        ImmutableMap.<String, Object>builder()
            .put("application", context.get("application"))
            .put("credentials", context.get("account"))
            .put("startApplication", context.get("startApplication"))
            .put("region", context.get("region"))
            .put("executionId", execution.getId())
            .put("trigger", execution.getTrigger().getOther())
            .put(
                "applicationArtifact",
                getCloudFoundryDeployArtifact(stage, context.get("applicationArtifact")))
            .put("manifest", manifestResult.getManifests());

    if (context.get("stack") != null) {
      operation.put("stack", context.get("stack"));
    }

    if (context.get("freeFormDetails") != null) {
      operation.put("freeFormDetails", context.get("freeFormDetails"));
    }

    return Collections.singletonList(
        ImmutableMap.<String, Object>builder().put(OPERATION, operation.build()).build());
  }

  private Artifact getCloudFoundryDeployArtifact(Stage stage, Object input) {
    CloudFoundryDeployArtifact applicationArtifactInput =
        mapper.convertValue(input, CloudFoundryDeployArtifact.class);
    Artifact artifact =
        artifactUtils.getBoundArtifactForStage(
            stage,
            applicationArtifactInput.getArtifactId(),
            applicationArtifactInput.getArtifact());
    if (artifact == null) {
      throw new IllegalArgumentException("Unable to bind the application artifact");
    }

    return artifact;
  }

  @Override
  public boolean isKatoResultExpected() {
    return false;
  }

  @Override
  public String getCloudProvider() {
    return "cloudfoundry";
  }

  @Override
  public Optional<String> getHealthProviderName() {
    return Optional.empty();
  }

  @Data
  private static class CloudFoundryDeployArtifact {
    @Nullable private String artifactId;

    @Nullable private Artifact artifact;
  }
}

@@ -1898,66 +1898,59 @@
     
-DeploymentManifest manifest =%0A        mapper.con
+Artifact manifestArtifact = resol
 ve
+A
 rt
-Value(
+ifact(stage, 
 cont
@@ -1972,34 +1972,8 @@
 st%22)
-, DeploymentManifest.class
 );%0A 
@@ -2160,28 +2160,24 @@
 manifest
-.get
 Artifact
 Id())%0A  
@@ -2168,17 +2168,23 @@
 Artifact
-I
+.getUui
 d())%0A   
@@ -2218,28 +2218,24 @@
 manifest
-.get
 Artifact
 ())%0A    
@@ -2226,18 +2226,16 @@
 Artifact
-()
 )%0A      
@@ -2273,28 +2273,24 @@
 manifest
-.get
 Artifact
 ().getAr
@@ -2281,18 +2281,16 @@
 Artifact
-()
 .getArti
@@ -2516,29 +2516,32 @@
 .Result 
-manifestResul
+evaluatedManifes
 t = mani
@@ -2588,16 +2588,17 @@
 ntext);%0A
+%0A
     fina
@@ -3110,33 +3110,16 @@
    .put(
-%0A                
 %22applica
@@ -3136,46 +3136,16 @@
 ct%22,
-%0A                getCloudFoundryDeploy
+ resolve
 Arti
@@ -3226,21 +3226,24 @@
 t%22, 
-manifestResul
+evaluatedManifes
 t.ge
@@ -3643,29 +3643,15 @@
 act 
-getCloudFoundryDeploy
+resolve
 Arti
@@ -3692,54 +3692,53 @@
     
-CloudFoundryDeployArtifact application
+StageContextArtifactView stageContext
 Artifact
 Inpu
@@ -3733,21 +3733,20 @@
 Artifact
-Input
+View
  =%0A     
@@ -3779,34 +3779,28 @@
 ut, 
-CloudFoundryDeploy
+StageContext
 Artifact
 .cla
@@ -3795,16 +3795,20 @@
 Artifact
+View
 .class);
@@ -3911,35 +3911,36 @@
         
-application
+stageContext
 Artifact
 Input.ge
@@ -3923,37 +3923,36 @@
 eContextArtifact
-Input
+View
 .getArtifactId()
@@ -3965,35 +3965,36 @@
         
-application
+stageContext
 Artifact
 Input.ge
@@ -3989,13 +3989,12 @@
 fact
-Input
+View
 .get
@@ -4443,34 +4443,28 @@
 ass 
-CloudFoundryDeploy
+StageContext
 Artifact
  %7B%0A 
@@ -4459,16 +4459,20 @@
 Artifact
+View
  %7B%0A    @
@@ -4507,17 +4507,16 @@
 factId;%0A
-%0A
     @Nul

Load manifest artifact before evaluating manifest (#3487)