/*
 * Copyright 2016 Google, 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.fiat.providers.internal;

import com.netflix.hystrix.exception.HystrixBadRequestException;
import com.netflix.spinnaker.fiat.model.resources.Application;
import com.netflix.spinnaker.fiat.model.resources.ServiceAccount;
import com.netflix.spinnaker.fiat.providers.HealthTrackable;
import com.netflix.spinnaker.fiat.providers.ProviderHealthTracker;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;

import java.util.List;
import java.util.concurrent.atomic.AtomicReference;

@Slf4j
public class Front50Service implements HealthTrackable, InitializingBean {

  private static final String GROUP_KEY = "front50Service";

  private final Front50Api front50Api;

  @Autowired
  @Getter
  private ProviderHealthTracker healthTracker;

  private AtomicReference<List<Application>> applicationCache = new AtomicReference<>();
  private AtomicReference<List<ServiceAccount>> serviceAccountCache = new AtomicReference<>();

  public Front50Service(Front50Api front50Api) {
    this.front50Api = front50Api;
  }

  @Override
  public void afterPropertiesSet() throws Exception {
    try {
      // Initialize caches (also indicates service is healthy)
      getAllApplicationPermissions();
      getAllServiceAccounts();
    } catch (Exception e) {
      log.warn("Cache prime failed: ", e);
    }
  }

  public List<Application> getAllApplicationPermissions() {
    return new SimpleJava8HystrixCommand<>(
        GROUP_KEY,
        "getAllApplicationPermissions",
        () -> {
          applicationCache.set(front50Api.getAllApplicationPermissions());
          healthTracker.success();
          return applicationCache.get();
        },
        (Throwable cause) -> {
          logFallback("application", cause);
          List<Application> applications = applicationCache.get();
          if (applications == null) {
            throw new HystrixBadRequestException("Front50 is unavailable", cause);
          }
          return applications;
        }).execute();
  }

  public List<ServiceAccount> getAllServiceAccounts() {
    return new SimpleJava8HystrixCommand<>(
        GROUP_KEY,
        "getAccounts",
        () -> {
          serviceAccountCache.set(front50Api.getAllServiceAccounts());
          healthTracker.success();
          return serviceAccountCache.get();
        },
        (Throwable cause) -> {
          logFallback("service account", cause);
          List<ServiceAccount> serviceAccounts = serviceAccountCache.get();
          if (serviceAccounts == null) {
            throw new HystrixBadRequestException("Front50 is unavailable", cause);
          }
          return serviceAccounts;
        }).execute();
  }

  private static void logFallback(String resource, Throwable cause) {
    String message = cause != null ? "Cause: " + cause.getMessage() : "";
    log.info("Falling back to {} cache. {}", resource, message);
  }
}

@@ -1142,16 +1142,76 @@
 towired;
+%0Aimport org.springframework.scheduling.annotation.Scheduled;
 %0A%0Aimport
@@ -1367,69 +1367,8 @@
  %7B%0A%0A
-  private static final String GROUP_KEY = %22front50Service%22;%0A%0A
   pr
@@ -1892,22 +1892,23 @@
 )%0A      
-getAll
+refresh
 Applicat
@@ -1910,26 +1910,16 @@
 lication
-Permission
 s();%0A   
@@ -1921,22 +1921,23 @@
 ;%0A      
-getAll
+refresh
 ServiceA
@@ -2104,847 +2104,542 @@
 urn 
-new SimpleJava8HystrixCommand%3C%3E(%0A        GROUP_KEY,%0A        %22getAllApplicationPermissions%22,%0A        () -%3E %7B%0A          applicationCache.set(front50Api.getAllApplicationPermissions());%0A          healthTracker.success();%0A          return applicationCache.get();%0A        %7D,%0A        (Throwable cause) -%3E %7B%0A          logFallback(%22application%22,
+applicationCache.get();%0A  %7D%0A%0A  public List%3CServiceAccount%3E getAllServiceAccounts() %7B%0A    return serviceAccountCache.get();%0A  %7D%0A%0A  private static void logFallback(String resource, Throwable
  cause)
-;%0A 
+ %7B%0A
     
-     List%3CApplication%3E applications = applicationCache.get();%0A          if (applications == null) %7B%0A            throw new HystrixBadRequestException(%22Front50 is unavailable%22, cause);%0A          %7D%0A          return applications;%0A        %7D).execute();%0A  %7D%0A%0A  public List%3CServiceAccount%3E getAllServiceAccounts() %7B%0A    return new SimpleJava8HystrixCommand%3C%3E(%0A        GROUP_KEY,%0A        %22getAccounts%22,%0A        () -%3E %7B%0A          serviceAccountCache.set(front50Api.getAllServiceAccount
+String message = cause != null ? %22Cause: %22 + cause.getMessage() : %22%22;%0A    log.info(%22Falling back to %7B%7D cache. %7B%7D%22, resource, message);%0A  %7D%0A%0A%0A  @Scheduled(fixedDelayString = %22$%7Bfiat.front50RefreshMs:30000%7D%22)%0A  public void refreshApplications() %7B%0A    applicationCache.set(%0A            front50Api.getAllApplicationPermission
 s()
-);
 %0A    
-  
+);%0A
     
@@ -2669,173 +2669,99 @@
 ;%0A  
-        return serviceAccountCache.get();%0A        %7D,%0A        (Throwable cause) -%3E %7B%0A          logFallback(%22service account%22, cause);%0A          List%3CServiceAccount%3E s
+%7D%0A%0A  @Scheduled(fixedDelayString = %22$%7Bfiat.front50RefreshMs:30000%7D%22)%0A  public void refreshS
 ervi
@@ -2770,18 +2770,24 @@
 Accounts
+() %7B%0A  
  
-=
  service
@@ -2799,22 +2799,20 @@
 ntCache.
-g
+s
 et(
-);
 %0A       
@@ -2818,152 +2818,28 @@
     
-if (serviceAccounts == null) %7B%0A            throw new HystrixBadRequestException(%22Front50 is unavailable%22, cause);%0A          %7D%0A          return s
+  front50Api.getAllS
 ervi
@@ -2852,243 +2852,44 @@
 unts
-;%0A 
+()%0A
     
-   %7D).execute();%0A  %7D%0A%0A  private static void logFallback(String resource, Throwable cause) %7B%0A    String message = cause != null ? %22Cause: %22 + cause.getMessage() : %22%22;%0A    log.info(%22Falling back to %7B%7D cache. %7B%7D%22, resource, message
+);%0A    healthTracker.success(
 );%0A 

Update Front50 cache periodically and serve live calls from cache. (#351)