<?php
/**
 * Resolve location rules into post types, taxonomies, and list-table labels.
 *
 * @package CustomFields
 * @since 1.9.0
 */

namespace CustomFields;

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

/**
 * Shared location target resolution (REST meta, admin columns, list table).
 */
final class LocationTargets {

	/**
	 * Post type keys targeted by location rules (supports == and !=).
	 *
	 * @param array<string, mixed> $rules Normalized location rules from LocationRules::get().
	 * @return array<int, string>
	 */
	public static function postTypesFromRules( array $rules ): array {
		$includes = [];
		$excludes = [];

		foreach ( (array) ( $rules['rules'] ?? [] ) as $rule ) {
			if ( ! is_array( $rule ) || (string) ( $rule['param'] ?? '' ) !== 'post_type' ) {
				continue;
			}

			$value = sanitize_key( (string) ( $rule['value'] ?? '' ) );
			if ( $value === '' ) {
				continue;
			}

			$operator = (string) ( $rule['operator'] ?? '==' );
			if ( $operator === '==' ) {
				$includes[] = $value;
			} elseif ( $operator === '!=' ) {
				$excludes[] = $value;
			}
		}

		if ( $includes !== [] ) {
			return array_values(
				array_filter(
					array_unique( $includes ),
					static fn( string $type ): bool => post_type_exists( $type )
				)
			);
		}

		if ( $excludes !== [] ) {
			$excludes = array_unique( $excludes );

			return array_values(
				array_filter(
					self::uiPostTypes(),
					static fn( string $type ): bool => ! in_array( $type, $excludes, true )
				)
			);
		}

		return [];
	}

	/**
	 * Taxonomy keys targeted by location rules (supports == and !=).
	 *
	 * @param array<string, mixed> $rules Normalized location rules.
	 * @return array<int, string>
	 */
	public static function taxonomiesFromRules( array $rules ): array {
		$includes = [];
		$excludes = [];

		foreach ( (array) ( $rules['rules'] ?? [] ) as $rule ) {
			if ( ! is_array( $rule ) || (string) ( $rule['param'] ?? '' ) !== 'taxonomy' ) {
				continue;
			}

			$value = sanitize_key( (string) ( $rule['value'] ?? '' ) );
			if ( $value === '' ) {
				continue;
			}

			$operator = (string) ( $rule['operator'] ?? '==' );
			if ( $operator === '==' ) {
				$includes[] = $value;
			} elseif ( $operator === '!=' ) {
				$excludes[] = $value;
			}
		}

		if ( $includes !== [] ) {
			return array_values(
				array_filter(
					array_unique( $includes ),
					static fn( string $tax ): bool => taxonomy_exists( $tax )
				)
			);
		}

		if ( $excludes !== [] ) {
			$excludes = array_unique( $excludes );

			return array_values(
				array_filter(
					self::uiTaxonomies(),
					static fn( string $tax ): bool => ! in_array( $tax, $excludes, true )
				)
			);
		}

		return [];
	}

	/**
	 * Human-readable location summary for the field group list table.
	 *
	 * @param array<string, mixed> $definition Field group definition.
	 */
	public static function listColumnHtml( array $definition ): string {
		$location_rules = LocationRules::get( $definition );
		$targets        = self::listTargets( $location_rules );

		if ( $targets === [] ) {
			return '<span class="cf-location-target cf-location-target--various">'
				. '<span class="dashicons dashicons-admin-generic" aria-hidden="true"></span> '
				. esc_html__( 'Various', 'wppowersuite-lite' )
				. '</span>';
		}

		$labels = array_column( $targets, 'label' );
		$total  = count( $labels );
		$labels = array_slice( $labels, 0, 3 );
		$icon   = (string) ( $targets[0]['icon'] ?? 'dashicons-admin-post' );
		$multi  = $total > 1 ? ' cf-location-target__icon--multi' : '';

		$html  = '<span class="cf-location-target">';
		$html .= '<span class="dashicons ' . esc_attr( $icon . $multi ) . '" aria-hidden="true"></span> ';
		$html .= esc_html( implode( ', ', $labels ) );
		if ( $total > 3 ) {
			$html .= esc_html__( ', …', 'wppowersuite-lite' );
		}
		$html .= '</span>';

		return $html;
	}

	/**
	 * @param array<string, mixed> $location_rules Normalized location rules.
	 * @return array<int, array{label: string, icon: string}>
	 */
	private static function listTargets( array $location_rules ): array {
		$targets = [];

		foreach ( (array) ( $location_rules['rules'] ?? [] ) as $rule ) {
			if ( ! is_array( $rule ) || (string) ( $rule['operator'] ?? '==' ) !== '==' ) {
				continue;
			}

			$param = (string) ( $rule['param'] ?? '' );
			$value = sanitize_key( (string) ( $rule['value'] ?? '' ) );
			if ( $value === '' ) {
				continue;
			}

			if ( $param === 'post_type' && post_type_exists( $value ) ) {
				$object = get_post_type_object( $value );
				if ( $object instanceof \WP_Post_Type ) {
					$targets[ 'post:' . $value ] = [
						'label' => (string) ( $object->labels->singular_name ?? $object->label ?? $value ),
						'icon'  => self::dashiconFromMenuIcon( (string) ( $object->menu_icon ?? '' ), 'dashicons-admin-post' ),
					];
				}
				continue;
			}

			if ( $param === 'taxonomy' && taxonomy_exists( $value ) ) {
				$taxonomy = get_taxonomy( $value );
				if ( $taxonomy instanceof \WP_Taxonomy ) {
					$targets[ 'tax:' . $value ] = [
						'label' => (string) ( $taxonomy->labels->singular_name ?? $taxonomy->label ?? $value ),
						'icon'  => 'dashicons-tag',
					];
				}
			}
		}

		return array_values( $targets );
	}

	/**
	 * @return array<int, string>
	 */
	private static function uiPostTypes(): array {
		$excluded = [
			'attachment',
			'wp_block',
			'wp_navigation',
			'wp_template',
			'wp_template_part',
			'wp_font_family',
			'wp_font_face',
		];

		return array_values(
			array_diff(
				array_keys( get_post_types( [ 'show_ui' => true ] ) ),
				$excluded
			)
		);
	}

	/**
	 * @return array<int, string>
	 */
	private static function uiTaxonomies(): array {
		return array_values(
			array_keys( get_taxonomies( [ 'show_ui' => true ] ) )
		);
	}

	/**
	 * @param string $menu_icon  Post type menu_icon value.
	 * @param string $fallback   Default dashicon class.
	 */
	private static function dashiconFromMenuIcon( string $menu_icon, string $fallback ): string {
		if ( $menu_icon === '' || $menu_icon === 'none' ) {
			return $fallback;
		}

		if ( str_starts_with( $menu_icon, 'dashicons-' ) ) {
			return $menu_icon;
		}

		return $fallback;
	}
}
