<?php
namespace R2_Offload\Media;

use R2_Offload\DB;
use R2_Offload\Settings;

defined( 'ABSPATH' ) || exit;

final class URL_Rewriter {

	private Settings $settings;
	private string $local_base_url;
	private string $remote_base_url;
	private string $prefix;

	public function __construct( Settings $settings ) {
		$this->settings        = $settings;
		$uploads               = wp_get_upload_dir();
		$this->local_base_url  = trailingslashit( $uploads['baseurl'] );
		$this->remote_base_url = $settings->cdn_base_url();
		$this->prefix          = $settings->effective_prefix();
	}

	public function register(): void {
		if ( ! $this->settings->get( 'rewrite_urls' ) || $this->remote_base_url === '' ) {
			return;
		}
		add_filter( 'wp_get_attachment_url', [ $this, 'filter_attachment_url' ], 20, 2 );
		add_filter( 'wp_get_attachment_image_src', [ $this, 'filter_image_src' ], 20, 4 );
		add_filter( 'wp_calculate_image_srcset', [ $this, 'filter_srcset' ], 20, 5 );
	}

	/** @var array<int,bool> request-level cache to avoid a DB hit per image/srcset entry */
	private array $offloaded_cache = [];

	private function is_offloaded( int $attachment_id ): bool {
		if ( ! isset( $this->offloaded_cache[ $attachment_id ] ) ) {
			$item = DB::get_item( $attachment_id );
			$this->offloaded_cache[ $attachment_id ] = $item && $item->status === 'offloaded';
		}
		return $this->offloaded_cache[ $attachment_id ];
	}

	private function to_remote( string $url ): string {
		if ( strpos( $url, $this->local_base_url ) !== 0 ) {
			return $url;
		}
		$relative = ltrim( substr( $url, strlen( $this->local_base_url ) ), '/' );
		$object   = $this->prefix !== '' ? $this->prefix . '/' . $relative : $relative;
		return $this->remote_base_url . '/' . $object;
	}

	public function filter_attachment_url( $url, $attachment_id ) {
		if ( ! $this->is_offloaded( (int) $attachment_id ) ) {
			return $url;
		}
		return $this->to_remote( (string) $url );
	}

	public function filter_image_src( $image, $attachment_id, $size, $icon ) {
		if ( ! is_array( $image ) || ! $this->is_offloaded( (int) $attachment_id ) ) {
			return $image;
		}
		$image[0] = $this->to_remote( (string) $image[0] );
		return $image;
	}

	public function filter_srcset( $sources, $size_array, $image_src, $image_meta, $attachment_id ) {
		if ( ! is_array( $sources ) || ! $this->is_offloaded( (int) $attachment_id ) ) {
			return $sources;
		}
		foreach ( $sources as &$src ) {
			if ( isset( $src['url'] ) ) {
				$src['url'] = $this->to_remote( (string) $src['url'] );
			}
		}
		return $sources;
	}
}
