<?php

namespace CelerSearch\SearchAreas;

use CelerSearch\Utilities\Logger;

/**
 * Registry for search area classes
 *
 * Maps search area type strings to their concrete class implementations
 * and manages which areas are active based on settings.
 */
class SearchAreaRegistry {

	/**
	 * Registered search area classes keyed by type
	 *
	 * @var array<string, string>
	 */
	private static array $classes = [];

	/**
	 * Cached instances of search areas
	 *
	 * @var array<string, AbstractSearchArea>
	 */
	private static array $instances = [];

	/**
	 * Register a search area class for a type
	 *
	 * @param string $type  The search area type identifier.
	 * @param string $class The fully qualified class name.
	 *
	 * @return void
	 */
	public static function register( string $type, string $class ): void {
		if ( ! is_subclass_of( $class, AbstractSearchArea::class ) ) {
			return;
		}

		self::$classes[ $type ] = $class;
	}

	/**
	 * Check if a type is registered
	 *
	 * @param string $type The search area type.
	 *
	 * @return bool
	 */
	public static function has( string $type ): bool {
		return isset( self::$classes[ $type ] );
	}

	/**
	 * Get the class name for a type
	 *
	 * @param string $type The search area type.
	 *
	 * @return string|null
	 */
	public static function get_class( string $type ): ?string {
		return self::$classes[ $type ] ?? null;
	}

	/**
	 * Create a search area instance from config
	 *
	 * @param array $config The search area configuration from settings.
	 *
	 * @return AbstractSearchArea|null
	 */
	public static function create_from_config( array $config ): ?AbstractSearchArea {
		$type = $config['type'] ?? '';

		if ( empty( $type ) || ! self::has( $type ) ) {
			return null;
		}

		$class = self::get_class( $type );

		return new $class( $config );
	}

	/**
	 * Get all registered types
	 *
	 * @return array<string>
	 */
	public static function get_registered_types(): array {
		return array_keys( self::$classes );
	}

	/**
	 * Get active search areas that have autocomplete enabled
	 *
	 * Reads from settings and returns instances for areas that:
	 * - Are enabled
	 * - Have autocomplete enabled
	 * - Have a registered class
	 *
	 * @return array<AbstractSearchArea>
	 */
	public static function get_active_areas(): array {
		$settings         = get_option( 'celersearch_settings', [] );
		$configured_areas = $settings['search_areas'] ?? [];

		Logger::channel( Logger::CHANNEL_DEBUG )->debug( 'get_active_areas() called', [
			'enable_search' => $settings['enable_search'] ?? 'not set',
			'areas_count'   => count( $configured_areas ),
		] );

		// Check master switch
		if ( empty( $settings['enable_search'] ) ) {
			Logger::channel( Logger::CHANNEL_DEBUG )->debug( 'Search disabled globally - returning empty' );
			return [];
		}

		$active = [];

		foreach ( $configured_areas as $config ) {
			$type         = $config['type'] ?? '';
			$enabled      = ! empty( $config['enabled'] );
			$ac_feature   = $config['features']['autocomplete'] ?? false;
			$autocomplete = is_array( $ac_feature ) ? ! empty( $ac_feature['enabled'] ) : ! empty( $ac_feature );

			Logger::channel( Logger::CHANNEL_DEBUG )->debug( 'Processing area', [
				'type'         => $type,
				'enabled'      => $enabled,
				'autocomplete' => $autocomplete,
			] );

			// Must be enabled and have autocomplete enabled
			if ( ! $enabled || ! $autocomplete ) {
				Logger::channel( Logger::CHANNEL_DEBUG )->debug( 'Area skipped - not enabled or no autocomplete', [ 'type' => $type ] );
				continue;
			}

			// Must have a valid type
			if ( empty( $type ) || ! self::has( $type ) ) {
				Logger::channel( Logger::CHANNEL_DEBUG )->debug( 'Area skipped - type not registered', [
					'type'             => $type,
					'registered_types' => self::get_registered_types(),
				] );
				continue;
			}

			// Create instance
			$area = self::create_from_config( $config );

			if ( $area && $area->supports_autocomplete() ) {
				$active[] = $area;
				Logger::channel( Logger::CHANNEL_DEBUG )->debug( 'Area added to active list', [ 'type' => $type ] );
			}
		}

		Logger::channel( Logger::CHANNEL_DEBUG )->debug( 'Active areas result', [ 'count' => count( $active ) ] );

		return (array) apply_filters( 'celersearch_active_autocomplete_areas', $active );
	}

	/**
	 * Get active areas for a specific context
	 *
	 * @param string $context The context ('frontend' or 'admin').
	 *
	 * @return array<AbstractSearchArea>
	 */
	public static function get_active_areas_for_context( string $context ): array {
		$areas = self::get_active_areas();

		Logger::channel( Logger::CHANNEL_DEBUG )->debug( 'get_active_areas_for_context()', [
			'context'      => $context,
			'total_active' => count( $areas ),
		] );

		$filtered = array_filter( $areas, function ( AbstractSearchArea $area ) use ( $context ) {
			$matches_context = $area->get_context() === $context;
			$should_attach   = $area->should_attach();

			Logger::channel( Logger::CHANNEL_DEBUG )->debug( 'Area filter check', [
				'type'          => $area->get_type(),
				'context_match' => $matches_context,
				'should_attach' => $should_attach,
			] );

			return $matches_context && $should_attach;
		} );

		Logger::channel( Logger::CHANNEL_DEBUG )->debug( 'Filtered areas result', [
			'context' => $context,
			'count'   => count( $filtered ),
		] );

		return $filtered;
	}

	/**
	 * Register default search area classes
	 *
	 * @return void
	 */
	public static function register_defaults(): void {
		// Frontend
		self::register( 'wordpress_public_search', PublicSearchArea::class );

		// WooCommerce (if active)
		if ( class_exists( 'WooCommerce' ) ) {
			self::register( 'woocommerce_product_search', WooCommerceProductSearchArea::class );
			self::register( 'woocommerce_shop_browse', WooCommerceShopBrowseArea::class );
			self::register( 'woocommerce_orders_search', WooCommerceOrdersSearchArea::class );
		}

		// Admin - register for each public post type
		$post_types = get_post_types( [ 'public' => true, 'show_ui' => true ], 'names' );
		foreach ( $post_types as $post_type ) {
			if ( $post_type === 'attachment' ) {
				continue;
			}
			self::register( 'admin_' . $post_type . '_search', AdminPostTypeSearchArea::class );
		}
	}

	/**
	 * Clear all registered classes (mainly for testing)
	 *
	 * @return void
	 */
	public static function clear(): void {
		self::$classes   = [];
		self::$instances = [];
	}
}
