<?php
/**
 * FrontPup Clear Cache Class
 */
if ( ! defined( 'ABSPATH' ) ) exit; // Exit if accessed directly

class FrontPup_Clear_Cache {

  private $settings = [];

  private $last_error = '';
  private $result = null;

  /**
   * Constructor
   */
  public function __construct( $settings = [] ) {
      $this->settings = $settings;
  }

  /**
   * Clear Cache method
   * 
   * @param array|null $tags Optional array of cache tags to invalidate.
   *                         If null or empty, clears entire cache (/*).
   *                         If array, converts to tag-based paths (#tag).
   * @return bool True on success, false on failure
   */
  public function clear_cache( $tags = null ) {
    // Convert empty array to null
    if ( is_array( $tags ) && empty( $tags ) ) {
      $tags = null;
    }

    // Build invalidation paths
    if ( $tags === null ) {
      $paths = ['/*'];  // Clear entire cache
    } else {
      $paths = [];
      foreach ( $tags as $tag ) {
        $paths[] = '#' . $tag;
      }
    }

    // Debug logging
    if ( defined( 'FRONTPUP_DEBUG' ) && FRONTPUP_DEBUG ) {
      error_log( 'FrontPup Clear Cache by Post Type: Invalidation paths = ' . print_r( $paths, true ) );
    }

    // Implement the logic to clear the cache using AWS CloudFront API
    $initOptions = ['version' => 'latest', 'region'  => FRONTPUP_REGION ];

    // We cannot move forward if we do not have a distribution ID
    if( empty($this->settings['distribution_id']) ) {
        $this->set_last_error( 'Distribution ID not set in settings' );
        return false;
    }

    $mode = isset($this->settings['credentials_mode']) ? $this->settings['credentials_mode'] : 'policy';
    switch( $mode ) {
      case 'wpconfig': {
        if( defined('FRONTPUP_ACCESS_KEY_ID') && defined('FRONTPUP_SECRET_ACCESS_KEY') ) {
            $initOptions['credentials'] = [
              'key'    => FRONTPUP_ACCESS_KEY_ID,
              'secret' => FRONTPUP_SECRET_ACCESS_KEY,
            ];
        } else {
            $this->set_last_error( 'FRONTPUP_ACCESS_KEY_ID or FRONTPUP_SECRET_ACCESS_KEY not defined in wp-config.php' );
            return false;
        }
      } break;
      case 'database': {
        if( isset($this->settings['access_key_id']) && isset($this->settings['secret_access_key']) ) {
            $initOptions['credentials'] = [
              'key'    => $this->settings['access_key_id'],
              'secret' => $this->settings['secret_access_key'],
            ];
        } else {
            $this->set_last_error( 'Access Key ID or Secret Access Key not set in settings' );
            return false;
        }
      } break;
      case 'policy':
      default: {
        // Use IAM Role or environment variables
        break;
      }
    }

    $sdk_mode = $this->settings['full_aws_sdk'] ?? '';

    // Three SDK paths: the lightweight custom SigV4 client (default), the
    // AsyncAws client (trimmed bundle), or the full AWS SDK for PHP.
    if( $sdk_mode === 'asyncaws' ) {
      /**
       * Load the AsyncAws CloudFront client (trimmed bundle)
       * ref: https://async-aws.com/clients/cloud-front.html
       */
      if ( !class_exists('AsyncAws\\CloudFront\\CloudFrontClient')) {
        if( !file_exists( plugin_dir_path( __FILE__ ) . 'asyncaws/vendor/autoload.php' ) ) {
          $this->set_last_error( __('The AsyncAws SDK is not available.', 'frontpup') );
          return false;
        }

        // Lets load our version of the AsyncAws SDK
        require_once plugin_dir_path( __FILE__ ) . 'asyncaws/vendor/autoload.php';
      }

      // Translate the shared $initOptions['credentials'] shape into AsyncAws's flat
      // Configuration options. When no explicit credentials are set (policy mode),
      // AsyncAws's own credential provider chain (env vars/ECS/IMDSv2/etc.) resolves them.
      $asyncOptions = [ 'region' => $initOptions['region'] ];
      if( !empty($initOptions['credentials']['key']) ) {
        $asyncOptions['accessKeyId'] = $initOptions['credentials']['key'];
        $asyncOptions['accessKeySecret'] = $initOptions['credentials']['secret'];
        if( !empty($initOptions['credentials']['token']) ) {
          $asyncOptions['sessionToken'] = $initOptions['credentials']['token'];
        }
      }

      try {
        $client = new AsyncAws\CloudFront\CloudFrontClient($asyncOptions);

        $response = $client->createInvalidation([
            'DistributionId' => $this->settings['distribution_id'],
            'InvalidationBatch' => [
                'CallerReference' => (string) time(),
                'Paths' => [
                    'Quantity' => count($paths),
                    'Items' => $paths,
                ],
            ],
        ]);

        // AsyncAws responses resolve lazily; force resolution now so that any
        // HTTP/auth error is thrown here instead of surfacing later (e.g. on
        // object destruction) where it can no longer be caught.
        $response->getInvalidation();
        $this->result = $response;

      } catch (\Throwable $e) {
        $this->set_last_error( $e->getMessage() ?: 'Unknown error occurred creating invalidation.' );
        return false;
      }
    } elseif( !empty($sdk_mode) ) {
      /**
       * Load AWS SDK (minimal)
       * ref: https://docs.aws.amazon.com/aws-sdk-php/v3/api/class-Aws.AwsClient.html#method___construct
       */
      if ( !class_exists('Aws\\Sdk')) { // AWS SDK was not loaded by another plugin
        if( !file_exists( plugin_dir_path( __FILE__ ) . 'aws/aws-autoloader.php' ) ) {
          $this->set_last_error( __('The full AWS SDK is not available.', 'frontpup') );
          return false;
        }
        
        // Lets load our version of the AWS SDK
        require_once plugin_dir_path( __FILE__ ) . 'aws/aws-autoloader.php';
      }
      
      if ( !class_exists('Aws\\CloudFront\\CloudFrontClient')) {
        $this->set_last_error( __('The full AWS CloudFront Client is not available.', 'frontpup') );
        return false;
      }

      try {
        $client = new Aws\CloudFront\CloudFrontClient($initOptions);

        $this->result = $client->createInvalidation([
            'DistributionId' => $this->settings['distribution_id'],
            'InvalidationBatch' => [
                'CallerReference' => (string) time(),
                'Paths' => [
                    'Quantity' => count($paths),
                    'Items' => $paths,
                ],
            ],
        ]);

      } catch (Aws\Exception\AwsException $e) {
        // Handle the exception if an error occurs
        // You can also get specific details about the AWS error
        //echo "AWS Error Code: " . $e->getAwsErrorCode() . "\n";
        //echo "AWS Error Message: " . $e->getAwsErrorMessage() . "\n";
        //echo "HTTP Status Code: " . $e->getStatusCode() . "\n";
        if( $e->getMessage() ) {
          $this->set_last_error( $e->getMessage() );
          return false;
        }
        $this->set_last_error( 'Unknown error occurred creating invalidation.' );
        return false;
      } catch (\Exception $e) {
        $this->set_last_error( $e->getMessage() );
        return false;
      }
    } else {
      /**
       * Lightweight AWS SDK path – no bundled AWS SDK required.
       */
      require_once plugin_dir_path( __FILE__ ) . 'includes/lightaws-cloudfront-wp.php';
 
      try {
        $cf = new LightAWS_CloudFront_WP( $initOptions );
        $this->result = $cf->createInvalidation($this->settings['distribution_id'], $paths );
 
      } catch (\Exception $e) {
        $this->set_last_error( $e->getMessage() );
        return false;
      }
    }

    // For demonstration, let's assume it returns true on success
    return true;
  }

  /**
   * Get last error message
   */
  public function get_last_error() {
    return $this->last_error;
  }

  /**
   * Set last error message
   */
  public function set_last_error( $message ) {
    $this->last_error = $message;
  }

  /**
   * Get result of last clear_cache operation
   */
  public function get_result() {
    return $this->result;
  }
}

// eof