package com.hubspot.baragon.service.edgecache.cloudflare;

import java.util.Collections;
import java.util.List;
import java.util.Optional;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.google.inject.Inject;
import com.hubspot.baragon.models.BaragonRequest;
import com.hubspot.baragon.service.config.EdgeCacheConfiguration;
import com.hubspot.baragon.service.edgecache.EdgeCache;
import com.hubspot.baragon.service.edgecache.cloudflare.client.CloudflareClient;
import com.hubspot.baragon.service.edgecache.cloudflare.client.CloudflareClientException;
import com.hubspot.baragon.service.edgecache.cloudflare.client.CloudflareDnsRecord;
import com.hubspot.baragon.service.edgecache.cloudflare.client.CloudflareZone;

/**
 * An implementation of a proxying edge cache backed by Cloudflare.
 *
 * Config example:
 * ...
 * edgeCache:
 *   enabled: true
 *   edgeCacheClass: CLOUDFLARE
 *   integrationSettings:
 *     apiBase: https://api.cloudflare.com/client/v4/
 *     apiEmail: email@host.net
 *     apiKey: some-key
 *     cacheTagFormat: cache-tag-for-%-service
 * ...
 */
public class CloudflareEdgeCache implements EdgeCache {
  private static final Logger LOG = LoggerFactory.getLogger(CloudflareEdgeCache.class);

  private final CloudflareClient cf;
  private final EdgeCacheConfiguration edgeCacheConfiguration;

  @Inject
  public CloudflareEdgeCache(CloudflareClient cf, EdgeCacheConfiguration edgeCacheConfiguration) {
    this.cf = cf;
    this.edgeCacheConfiguration = edgeCacheConfiguration;
  }

  /**
   * Invalidation will eventually occur when the TTL expires, so it's not a showstopper if this fails.
   */
  @Override
  public boolean invalidateIfNecessary(BaragonRequest request) {
    if (!request.getLoadBalancerService().getEdgeCacheDNS().isPresent()) {
      return false;
    }

    try {
      String edgeCacheDNS = request.getLoadBalancerService().getEdgeCacheDNS().get();
      Optional<CloudflareZone> matchingZone = getCloudflareZone(edgeCacheDNS);

      if (!matchingZone.isPresent()) {
        LOG.warn("`edgeCacheDNS` was defined on the request, but no matching Cloudflare Zone was found!");
        return false;
      }

      String zoneId = matchingZone.get().getId();
      Optional<CloudflareDnsRecord> matchingDnsRecord = getCloudflareDnsRecord(edgeCacheDNS, zoneId);

      if (!matchingDnsRecord.isPresent()) {
        LOG.warn("`edgeCacheDNS` was defined on the request, but no matching Cloudflare DNS Record was found!");
        return false;
      }

      if (!matchingDnsRecord.get().isProxied()) {
        LOG.warn("`edgeCacheDNS` was defined on the request, but {} is not a proxied DNS record!", edgeCacheDNS);
        return false;
      }

      return cf.purgeCache(
          zoneId,
          Collections.singletonList(
              String.format(
                  edgeCacheConfiguration.getIntegrationSettings().get("cacheTagFormat"),
                  request.getLoadBalancerService().getServiceId()
              )
          )
      );

    } catch (CloudflareClientException e) {
      LOG.error("Unable to invalidate Cloudflare cache for request {}", request, e);
      return false;
    }
  }

  private Optional<CloudflareDnsRecord> getCloudflareDnsRecord(String edgeCacheDNS, String zoneId) throws CloudflareClientException {
    List<CloudflareDnsRecord> dnsRecords = cf.listDnsRecords(zoneId);

    return dnsRecords.stream()
        .filter(r -> r.getZoneName().equals(edgeCacheDNS))
        .findAny();
  }

  private Optional<CloudflareZone> getCloudflareZone(String edgeCacheDNS) throws CloudflareClientException {
    List<CloudflareZone> zones = cf.getAllZones();
    String[] domainTokens = edgeCacheDNS.split("\\.");
    String baseDomain = String.format("%s.%s", domainTokens[domainTokens.length - 2], domainTokens[domainTokens.length - 1]);

    return zones.stream()
        .filter(z -> z.getName().equals(baseDomain))
        .findAny();
  }

}

@@ -2720,98 +2720,25 @@
     
-return cf.purgeCache(%0A          zoneId,%0A          Collections.singletonList(%0A             
+String cacheTag =
  Str
@@ -2759,24 +2759,16 @@
         
-   
-     
 edgeCach
@@ -2840,24 +2840,16 @@
         
-        
 request.
@@ -2898,36 +2898,206 @@
     
+);%0A%0A
       
-  )%0A          )%0A      
+LOG.debug(%22Sending cache purge request against %7B%7D for %7B%7D to Cloudflare...%22, matchingZone.get().getName(), cacheTag);%0A%0A      return cf.purgeCache(zoneId, Collections.singletonList(cacheTag)
 );%0A%0A

Add logging.