<?php
namespace R2_Offload\Media;

defined( 'ABSPATH' ) || exit;

final class Path_Resolver {

	public static function attachment_files( int $attachment_id ): array {
		$file = get_attached_file( $attachment_id );
		if ( ! $file ) {
			return [];
		}

		$files = [];
		if ( file_exists( $file ) ) {
			$files[] = $file;
		} else {
			// Original missing (pruned / webp-only) — still pick up sidecar variants on disk.
			foreach ( self::sidecar_candidates( $file ) as $candidate ) {
				if ( file_exists( $candidate ) ) {
					$files[] = $candidate;
				}
			}
			if ( empty( $files ) ) {
				return [];
			}
		}

		$meta = wp_get_attachment_metadata( $attachment_id );
		$dir  = trailingslashit( dirname( $file ) );

		if ( is_array( $meta ) && ! empty( $meta['sizes'] ) ) {
			foreach ( $meta['sizes'] as $size ) {
				if ( empty( $size['file'] ) ) {
					continue;
				}
				$candidate = $dir . $size['file'];
				if ( file_exists( $candidate ) ) {
					$files[] = $candidate;
				}
			}
		}

		// Discover sidecar webp/avif variants for every known path.
		$discovered = $files;
		foreach ( $files as $path ) {
			foreach ( self::sidecar_candidates( $path ) as $variant ) {
				if ( file_exists( $variant ) ) {
					$discovered[] = $variant;
				}
			}
		}

		return array_values( array_unique( $discovered ) );
	}

	/**
	 * Possible webp/avif companion paths for a given image path.
	 * Covers `file.jpg.webp`, `file.webp`, and size variants.
	 *
	 * @return string[]
	 */
	public static function sidecar_candidates( string $path ): array {
		$out = [];
		foreach ( [ '.webp', '.avif' ] as $ext ) {
			$out[] = $path . $ext;
			$replaced = preg_replace( '/\.(jpe?g|png|gif)$/i', $ext, $path );
			if ( $replaced && $replaced !== $path ) {
				$out[] = $replaced;
			}
		}
		return $out;
	}

	/**
	 * Relative object paths (uploads-basedir-relative) derived purely from
	 * attachment metadata — does NOT require the local files to exist. Used for
	 * remote cleanup after local copies were pruned.
	 *
	 * @return string[]
	 */
	public static function relative_paths_from_meta( int $attachment_id, string $basedir ): array {
		$file = get_attached_file( $attachment_id );
		if ( ! $file ) {
			return [];
		}
		$base  = trailingslashit( $basedir );
		$paths = [ $file ];
		$meta  = wp_get_attachment_metadata( $attachment_id );
		$dir   = trailingslashit( dirname( $file ) );

		if ( is_array( $meta ) && ! empty( $meta['sizes'] ) ) {
			foreach ( $meta['sizes'] as $size ) {
				if ( ! empty( $size['file'] ) ) {
					$paths[] = $dir . $size['file'];
				}
			}
		}

		foreach ( $paths as $p ) {
			foreach ( self::sidecar_candidates( $p ) as $variant ) {
				$paths[] = $variant;
			}
		}

		$relative = [];
		foreach ( array_unique( $paths ) as $p ) {
			$relative[] = ltrim( str_replace( $base, '', $p ), '/' );
		}
		return array_values( array_unique( $relative ) );
	}

	/**
	 * Absolute path for an uploads-relative file.
	 */
	public static function absolute_from_relative( string $relative ): string {
		$uploads = wp_get_upload_dir();
		return trailingslashit( $uploads['basedir'] ) . ltrim( str_replace( '\\', '/', $relative ), '/' );
	}

	/**
	 * Whether a filename should be ignored while walking extra upload dirs.
	 */
	public static function should_skip_file( string $basename ): bool {
		$basename = strtolower( $basename );
		if ( $basename === '.ds_store' || $basename === 'thumbs.db' || $basename === 'desktop.ini' ) {
			return true;
		}
		if ( str_starts_with( $basename, '.' ) ) {
			return true;
		}
		return false;
	}
}
