<?php
/**
 * Locations Manager.
 *
 * Centralized management of available display locations for price layouts.
 * Locations are extensible via the 'oppb_available_locations' filter.
 *
 * @package OpusPriceBuilder
 */

declare(strict_types=1);

namespace OpusPriceBuilder;

/**
 * Manages available display locations for price layouts.
 *
 * By default, only 'single_product' and 'loop' locations are enabled.
 * Developers can extend this via the 'oppb_available_locations' filter:
 *
 * @example Enable cart and checkout locations:
 * ```php
 * add_filter( 'oppb_available_locations', function( $locations ) {
 *     $locations['cart'] = [
 *         'label' => __( 'Cart', 'my-plugin' ),
 *         'description' => __( 'Cart page item prices', 'my-plugin' ),
 *     ];
 *     $locations['checkout'] = [
 *         'label' => __( 'Checkout', 'my-plugin' ),
 *         'description' => __( 'Checkout page item prices', 'my-plugin' ),
 *     ];
 *     return $locations;
 * } );
 * ```
 */
class Locations {

	/**
	 * Cached locations.
	 *
	 * @var array<string, array{label: string, description: string}>|null
	 */
	private static ?array $cachedLocations = null;

	/**
	 * Get all available locations.
	 *
	 * @return array<string, array{label: string, description: string}>
	 */
	public static function getAll(): array {
		if ( null !== self::$cachedLocations ) {
			return self::$cachedLocations;
		}

		$default_locations = array(
			'single_product' => array(
				'label'       => __( 'Single Product', 'opus-price-builder' ),
				'description' => __( 'Main product page price display', 'opus-price-builder' ),
			),
			'loop'           => array(
				'label'       => __( 'Loop', 'opus-price-builder' ),
				'description' => __( 'Shop, category, archive pages and related products', 'opus-price-builder' ),
			),
		);

		/**
		 * Filter the available display locations.
		 *
		 * Allows developers to add custom locations or enable cart/checkout.
		 *
		 * @param array<string, array{label: string, description: string}> $locations Default locations.
		 * @return array<string, array{label: string, description: string}> Modified locations.
		 *
		 * @example Enable cart location:
		 * ```php
		 * add_filter( 'oppb_available_locations', function( $locations ) {
		 *     $locations['cart'] = [
		 *         'label' => __( 'Cart', 'my-plugin' ),
		 *         'description' => __( 'Cart page item prices', 'my-plugin' ),
		 *     ];
		 *     return $locations;
		 * } );
		 * ```
		 */
		self::$cachedLocations = apply_filters( 'oppb_available_locations', $default_locations ); // phpcs:ignore WordPress.NamingConventions.PrefixAllGlobals.NonPrefixedHooknameFound

		return self::$cachedLocations;
	}

	/**
	 * Get location keys only.
	 *
	 * @return array<string>
	 */
	public static function getKeys(): array {
		return array_keys( self::getAll() );
	}

	/**
	 * Check if a location is valid/available.
	 *
	 * @param string $location The location key to check.
	 * @return bool
	 */
	public static function isValid( string $location ): bool {
		return array_key_exists( $location, self::getAll() );
	}

	/**
	 * Get a single location's data.
	 *
	 * @param string $location The location key.
	 * @return array{label: string, description: string}|null
	 */
	public static function get( string $location ): ?array {
		$locations = self::getAll();
		return $locations[ $location ] ?? null;
	}

	/**
	 * Get locations formatted for REST API response.
	 *
	 * @return array<string, array{label: string, description: string, key: string}>
	 */
	public static function getForApi(): array {
		$locations = self::getAll();
		$formatted = array();

		foreach ( $locations as $key => $data ) {
			$formatted[ $key ] = array_merge( $data, array( 'key' => $key ) );
		}

		return $formatted;
	}

	/**
	 * Get locations formatted for React admin (simple array with key, label, description).
	 *
	 * @return array<array{key: string, label: string, description: string}>
	 */
	public static function getForAdmin(): array {
		$locations = self::getAll();
		$result    = array();

		foreach ( $locations as $key => $data ) {
			$result[] = array(
				'key'         => $key,
				'label'       => $data['label'],
				'description' => $data['description'],
			);
		}

		return $result;
	}

	/**
	 * Clear the cached locations.
	 * Useful when filters may have changed.
	 *
	 * @return void
	 */
	public static function clearCache(): void {
		self::$cachedLocations = null;
	}

	/**
	 * Get the default location (first available).
	 *
	 * @return string
	 */
	public static function getDefault(): string {
		$keys = self::getKeys();
		return $keys[0] ?? 'single_product';
	}

	/**
	 * Validate and sanitize a location key.
	 * Returns the location if valid, or the default if invalid.
	 *
	 * @param string $location The location to validate.
	 * @return string Valid location key.
	 */
	public static function sanitize( string $location ): string {
		return self::isValid( $location ) ? $location : self::getDefault();
	}
}
