<?php
/**
 * Detect which theme or plugin registered each thumbnail size.
 *
 * @package CoffeeWP_Media_Cleanup
 */

namespace CWPM\Source;

use CWPM\Thumbnail\Sizes;

defined( 'ABSPATH' ) || exit;

class Detector {

	/**
	 * Detect the source of each registered thumbnail size.
	 *
	 * @param array $registered Output of wp_get_registered_image_subsizes().
	 * @return array Map of size name => [ 'type' => string, 'name' => string ].
	 */
	public static function detect( $registered ) {
		$sources    = array();
		$core_sizes = Sizes::get_core_sizes();

		foreach ( $core_sizes as $name ) {
			$sources[ $name ] = array(
				'type' => 'core',
				'name' => 'WordPress',
			);
		}

		$file_map = self::scan_for_sizes();
		$non_core = array_diff( array_keys( $registered ), $core_sizes );

		foreach ( $non_core as $name ) {
			if ( isset( $file_map[ $name ] ) ) {
				$sources[ $name ] = $file_map[ $name ];
			} else {
				$sources[ $name ] = array(
					'type' => 'core',
					'name' => 'WordPress',
				);
			}
		}

		return $sources;
	}

	/**
	 * Scan active theme and plugin entry files for add_image_size() calls.
	 *
	 * Only scans files where sizes are typically registered:
	 * - Theme: functions.php and inc/ directory (one level)
	 * - Plugins: main plugin file only
	 *
	 * @return array Map of size name => [ 'type' => string, 'name' => string ].
	 */
	private static function scan_for_sizes() {
		$map     = array();
		$pattern = '/\b(?:add_image_size|set_post_thumbnail_size)\s*\(\s*[\'"]([^\'"]+)[\'"]/';

		self::scan_theme( $map, $pattern );
		self::scan_plugins( $map, $pattern );

		return $map;
	}

	/**
	 * Scan active theme for size registrations.
	 *
	 * @param array  $map     Reference to results map.
	 * @param string $pattern Regex pattern.
	 */
	private static function scan_theme( &$map, $pattern ) {
		$theme      = wp_get_theme();
		$theme_dirs = array( get_template_directory() );

		if ( get_stylesheet_directory() !== get_template_directory() ) {
			$theme_dirs[] = get_stylesheet_directory();
		}

		foreach ( $theme_dirs as $dir ) {
			$theme_name = ( $dir === get_stylesheet_directory() )
				? $theme->get( 'Name' )
				: wp_get_theme( get_template() )->get( 'Name' );

			$files = self::get_theme_files( $dir );
			foreach ( $files as $file ) {
				$found = self::grep_file( $file, $pattern );
				foreach ( $found as $size_name ) {
					$map[ $size_name ] = array(
						'type' => 'theme',
						'name' => $theme_name,
					);
				}
			}
		}
	}

	/**
	 * Scan active plugins for size registrations.
	 *
	 * @param array  $map     Reference to results map.
	 * @param string $pattern Regex pattern.
	 */
	private static function scan_plugins( &$map, $pattern ) {
		if ( ! function_exists( 'get_plugin_data' ) ) {
			require_once ABSPATH . 'wp-admin/includes/plugin.php';
		}

		$active_plugins = get_option( 'active_plugins', array() );

		foreach ( $active_plugins as $plugin_file ) {
			$plugin_path = WP_PLUGIN_DIR . '/' . $plugin_file;

			if ( ! file_exists( $plugin_path ) ) {
				continue;
			}

			$plugin_dir = dirname( $plugin_path );

			if ( $plugin_dir === CWPM_PATH ) {
				continue;
			}

			$plugin_data = get_plugin_data( $plugin_path, false, false );
			$plugin_name = ! empty( $plugin_data['Name'] ) ? $plugin_data['Name'] : basename( $plugin_dir );

			$found = self::grep_file( $plugin_path, $pattern );
			foreach ( $found as $size_name ) {
				$map[ $size_name ] = array(
					'type' => 'plugin',
					'name' => $plugin_name,
				);
			}
		}
	}

	/**
	 * Get theme files likely to contain add_image_size() calls.
	 *
	 * Returns functions.php and PHP files in inc/ (one level deep).
	 *
	 * @param string $dir Theme directory.
	 * @return string[] Array of file paths.
	 */
	private static function get_theme_files( $dir ) {
		$files = array();

		$functions = $dir . '/functions.php';
		if ( file_exists( $functions ) ) {
			$files[] = $functions;
		}

		$inc_dir = $dir . '/inc';
		if ( is_dir( $inc_dir ) ) {
			$items = scandir( $inc_dir );
			foreach ( $items as $item ) {
				if ( '.' === $item || '..' === $item ) {
					continue;
				}
				$path = $inc_dir . '/' . $item;
				if ( is_file( $path ) && 'php' === pathinfo( $path, PATHINFO_EXTENSION ) ) {
					$files[] = $path;
				}
			}
		}

		return $files;
	}

	/**
	 * Search a single file for size names matching a pattern.
	 *
	 * @param string $file    File path.
	 * @param string $pattern PCRE pattern with one capture group.
	 * @return string[] Matched size names.
	 */
	private static function grep_file( $file, $pattern ) {
		// phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents -- reading local theme/plugin PHP file to detect image-size registrations; WP_Filesystem unnecessary.
		$contents = file_get_contents( $file );
		if ( false === $contents ) {
			return array();
		}

		if ( preg_match_all( $pattern, $contents, $matches ) ) {
			return $matches[1];
		}

		return array();
	}
}
