<?php
/**
 * BaseCloud Boost — BunnyCDN Integration
 *
 * Hooks into the BCB purge action system so that whenever the local
 * page cache is cleared, the corresponding BunnyCDN Pull Zone cache is
 * purged automatically via the BunnyCDN API.
 *
 * Setup requirements (WP Admin → BaseCloud Boost → CDN):
 *   - BunnyCDN Account API Key  (bunny.net → Account → API)
 *   - Pull Zone ID              (bunny.net → CDN → your pull zone → General → ID)
 *
 * API reference: https://docs.bunny.net/reference/
 *
 * @package BaseCloud\Boost\CDN
 */

declare( strict_types=1 );

namespace BaseCloud\Boost\CDN;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * BunnyCDN integration — registers purge hooks and exposes API helpers.
 */
class BunnyCDN_Integration {

	private const BUNNY_API_BASE  = 'https://api.bunny.net';
	private const PURGE_ENDPOINT  = 'https://api.bunny.net/purge';

	/**
	 * Register hooks that mirror BCB's local purge events to BunnyCDN.
	 *
	 * @return void
	 */
	public function boot(): void {
		// Full site purge.
		add_action( 'BCBOOST_after_purge_all',  [ $this, 'purge_all' ] );

		// Single URL purge.
		add_action( 'BCBOOST_after_purge_url',  [ $this, 'purge_url' ] );

		// Smart post purge (receives the full list of affected URLs).
		add_action( 'BCBOOST_after_purge_post', [ $this, 'on_purge_post' ], 10, 2 );

		// Taxonomy term purge.
		add_action( 'BCBOOST_after_purge_term', [ $this, 'on_purge_term' ], 10, 2 );
	}

	/**
	 * Purge every cached asset in the BunnyCDN Pull Zone.
	 *
	 * Calls POST /pullzone/{pullZoneId}/purgeCache — no request body needed.
	 *
	 * @return bool
	 */
	public function purge_all(): bool {
		if ( ! $this->is_configured() ) {
			return false;
		}

		$pull_zone_id = absint( BCBOOST_get_option( 'bunnycdn_pull_zone_id', 0 ) );
		$api_key      = (string) BCBOOST_get_option( 'bunnycdn_api_key', '' );

		$response = wp_remote_post(
			self::BUNNY_API_BASE . '/pullzone/' . $pull_zone_id . '/purgeCache',
			[
				'headers' => [
					'AccessKey'    => $api_key,
					'Content-Type' => 'application/json',
				],
				'timeout' => 15,
			]
		);

		if ( is_wp_error( $response ) ) {
			$this->log_error( 'purge_all: ' . $response->get_error_message() );
			return false;
		}

		$code = (int) wp_remote_retrieve_response_code( $response );
		return $code >= 200 && $code < 300;
	}

	/**
	 * Purge a single URL from BunnyCDN's edge cache.
	 *
	 * @param string $url Full URL to purge.
	 * @return bool
	 */
	public function purge_url( string $url ): bool {
		return $this->purge_urls( [ $url ] );
	}

	/**
	 * Purge multiple URLs. BunnyCDN handles each URL as a separate API call.
	 *
	 * @param string[] $urls List of full URLs.
	 * @return bool True if all requests succeeded.
	 */
	public function purge_urls( array $urls ): bool {
		if ( ! $this->is_configured() || empty( $urls ) ) {
			return false;
		}

		$api_key = (string) BCBOOST_get_option( 'bunnycdn_api_key', '' );
		$success = true;

		$urls = array_values( array_unique( array_filter( $urls ) ) );

		foreach ( $urls as $url ) {
			$response = wp_remote_post(
				add_query_arg(
					[ 'url' => rawurlencode( $url ), 'async' => 'false' ],
					self::PURGE_ENDPOINT
				),
				[
					'headers' => [
						'AccessKey'    => $api_key,
						'Content-Type' => 'application/json',
					],
					'timeout' => 10,
				]
			);

			if ( is_wp_error( $response ) ) {
				$this->log_error( 'purge_url ' . $url . ': ' . $response->get_error_message() );
				$success = false;
				continue;
			}

			$code = (int) wp_remote_retrieve_response_code( $response );
			if ( $code < 200 || $code >= 300 ) {
				$success = false;
			}
		}

		return $success;
	}

	/**
	 * Called after a post purge — receives the full URL list.
	 *
	 * @param int      $post_id Post ID (unused, URLs already resolved).
	 * @param string[] $urls    URLs that were purged locally.
	 * @return void
	 */
	public function on_purge_post( int $post_id, array $urls ): void {
		$this->purge_urls( $urls );
	}

	/**
	 * Called after a taxonomy term purge.
	 *
	 * @param int    $term_id  Term ID.
	 * @param string $taxonomy Taxonomy slug.
	 * @return void
	 */
	public function on_purge_term( int $term_id, string $taxonomy ): void {
		$term_link = get_term_link( $term_id, $taxonomy );
		if ( ! is_wp_error( $term_link ) ) {
			$this->purge_urls( [ $term_link, home_url( '/' ) ] );
		}
	}

	/**
	 * Test the configured credentials by fetching pull zone info.
	 *
	 * @return array{success: bool, message: string}
	 */
	public function test_connection(): array {
		$api_key      = (string) BCBOOST_get_option( 'bunnycdn_api_key', '' );
		$pull_zone_id = absint( BCBOOST_get_option( 'bunnycdn_pull_zone_id', 0 ) );

		if ( empty( $api_key ) ) {
			return [ 'success' => false, 'message' => __( 'BunnyCDN API Key is required.', 'basecloud-boost' ) ];
		}

		if ( empty( $pull_zone_id ) ) {
			return [ 'success' => false, 'message' => __( 'BunnyCDN Pull Zone ID is required.', 'basecloud-boost' ) ];
		}

		$response = wp_remote_get(
			self::BUNNY_API_BASE . '/pullzone/' . $pull_zone_id,
			[
				'headers' => [
					'AccessKey'    => $api_key,
					'Content-Type' => 'application/json',
				],
				'timeout' => 10,
			]
		);

		if ( is_wp_error( $response ) ) {
			return [ 'success' => false, 'message' => $response->get_error_message() ];
		}

		$code = (int) wp_remote_retrieve_response_code( $response );

		if ( $code === 401 ) {
			return [ 'success' => false, 'message' => __( 'Invalid API Key. Check your BunnyCDN Account API Key.', 'basecloud-boost' ) ];
		}

		if ( $code === 404 ) {
			return [ 'success' => false, 'message' => __( 'Pull Zone ID not found. Verify the numeric ID in your BunnyCDN dashboard.', 'basecloud-boost' ) ];
		}

		if ( $code < 200 || $code >= 300 ) {
			return [ 'success' => false, 'message' => sprintf( __( 'BunnyCDN returned HTTP %d.', 'basecloud-boost' ), $code ) ];
		}

		$body = (array) json_decode( wp_remote_retrieve_body( $response ), true );
		$name = $body['Name'] ?? __( 'Unknown', 'basecloud-boost' );
		$host = $body['Hostnames'][0]['Value'] ?? '';

		return [
			'success' => true,
			'message' => sprintf(
				/* translators: 1: pull zone name 2: hostname */
				__( 'Connected. Pull Zone: %1$s%2$s', 'basecloud-boost' ),
				$name,
				$host ? ' — ' . $host : ''
			),
		];
	}

	// ─── Private ──────────────────────────────────────────────────────────────

	/**
	 * Whether valid credentials are saved.
	 *
	 * @return bool
	 */
	private function is_configured(): bool {
		return ! empty( BCBOOST_get_option( 'bunnycdn_api_key', '' ) ) &&
		       ! empty( BCBOOST_get_option( 'bunnycdn_pull_zone_id', 0 ) );
	}

	/**
	 * Log an error message when WP_DEBUG_LOG is enabled.
	 *
	 * @param string $message Error detail.
	 * @return void
	 */
	private function log_error( string $message ): void {
		if ( defined( 'WP_DEBUG_LOG' ) && WP_DEBUG_LOG ) {
			error_log( '[BaseCloud Boost] BunnyCDN: ' . $message );
		}
	}
}
