<?php
/**
 * Recommendations config reader.
 *
 * @package PRECO
 */

namespace PRECO\Includes\Frontend\Core;

defined( 'ABSPATH' ) || exit;

/**
 * Reads and normalizes recommendations configuration.
 */
class RecommendationsConfig {

	/**
	 * Prefix for the per-page-type option names,
	 * e.g. 'cart' -> 'preco_recommendations_cart'.
	 */
	const OPTION_PREFIX = 'preco_recommendations_';

	/**
	 * Every page key that gets its own option row, mirroring how
	 * `preco_order_bumps` / `preco_popup_upsells` each get their own option
	 * instead of one big shared blob.
	 *
	 * @var string[]
	 */
	const PAGE_KEYS = array(
		'product-page',
		'shop-page',
		'product-archive',
		'thank-you',
		'cart',
		'checkout',
	);

	/**
	 * Human-readable label per page key. Single source of truth for both the
	 * builder's page list and the AI prompt context.
	 *
	 * @var array<string,string>
	 */
	const PAGE_LABELS = array(
		'product-page'    => 'Product Page',
		'shop-page'       => 'Shop Page',
		'product-archive' => 'Product Archive',
		'thank-you'       => 'Thank You Page',
		'cart'            => 'Cart Page',
		'checkout'        => 'Checkout Page',
	);

	/**
	 * Location keys available per page, in display order. Single source of
	 * truth for the default recommendations structure, the frontend
	 * builder's location list, and AI location validation.
	 *
	 * @var array<string,string[]>
	 */
	const LOCATION_KEYS = array(
		'product-page'    => array(
			'before-add-to-cart',
			'after-add-to-cart',
			'before-product-tabs',
			'after-product-tabs',
			'after-product-meta',
		),
		'shop-page'       => array(
			'before-product-loop',
			'after-product-loop',
			'no-results',
		),
		'product-archive' => array(
			'before-product-loop',
			'after-product-loop',
			'no-results',
		),
		'thank-you'       => array(
			'after-order-details',
		),
		'cart'            => array(
			'before-cart',
			'after-cart',
			'after-cart-totals',
		),
		'checkout'        => array(
			'before-checkout-form',
			'after-checkout-form',
			'after-checkout-order-totals',
		),
	);

	/**
	 * Location keys for a page, or an empty array for an unknown page.
	 *
	 * @param string $page_key Page key.
	 * @return string[]
	 */
	public static function get_location_keys( $page_key ) {
		return isset( self::LOCATION_KEYS[ $page_key ] ) ? self::LOCATION_KEYS[ $page_key ] : array();
	}

	/**
	 * Turn a hyphen/underscore key into a display label,
	 * e.g. 'before-add-to-cart' -> 'Before Add To Cart'.
	 *
	 * @param string $key Raw key.
	 * @return string
	 */
	public static function humanize_key( $key ) {
		return ucwords( str_replace( array( '-', '_' ), ' ', (string) $key ) );
	}

	/**
	 * Build the option name that stores a single page's config.
	 *
	 * @param string $page_key Page key.
	 * @return string
	 */
	public static function option_name_for_page( $page_key ) {
		return self::OPTION_PREFIX . str_replace( '-', '_', (string) $page_key );
	}

	/**
	 * Get raw stored configuration for a single page.
	 *
	 * @param string $page_key Page key.
	 * @return array
	 */
	public function get_raw( $page_key ) {
		$stored = get_option( self::option_name_for_page( $page_key ), array() );
		return is_array( $stored ) ? $stored : array();
	}

	/**
	 * Whether a page is enabled.
	 *
	 * @param string $page_key Page key.
	 * @return bool
	 */
	public function is_page_enabled( $page_key ) {
		$page     = $this->get_raw( $page_key );
		$settings = isset( $page['settings'] ) && is_array( $page['settings'] ) ? $page['settings'] : array();
		return ! ( isset( $settings['enabled'] ) && false === $settings['enabled'] );
	}

	/**
	 * Get location data for a given page/location.
	 *
	 * @param string $page_key Page key.
	 * @param string $location_key Location key.
	 * @return array
	 */
	public function get_location( $page_key, $location_key ) {
		$page      = $this->get_raw( $page_key );
		$locations = isset( $page['locations'] ) && is_array( $page['locations'] ) ? $page['locations'] : array();
		$loc       = isset( $locations[ $location_key ] ) && is_array( $locations[ $location_key ] ) ? $locations[ $location_key ] : array();

		$recommended_lists = array();
		if ( isset( $loc['recommendedLists'] ) && is_array( $loc['recommendedLists'] ) ) {
			$recommended_lists = $this->normalize_list_array( $loc['recommendedLists'] );
		}

		return array(
			'settings'         => isset( $loc['settings'] ) && is_array( $loc['settings'] ) ? $loc['settings'] : array(),
			'recommendedLists' => $recommended_lists,
		);
	}

	/**
	 * Normalize a list array that might be saved as associative numeric keys.
	 *
	 * @param array $lists Raw lists.
	 * @return array
	 */
	private function normalize_list_array( $lists ) {
		if ( empty( $lists ) ) {
			return array();
		}

		$is_numeric_keyed = true;
		foreach ( array_keys( $lists ) as $k ) {
			if ( ! is_int( $k ) && ! ( is_string( $k ) && ctype_digit( $k ) ) ) {
				$is_numeric_keyed = false;
				break;
			}
		}

		if ( $is_numeric_keyed ) {
			ksort( $lists );
			$lists = array_values( $lists );
		}

		$out = array();
		foreach ( $lists as $list ) {
			$out[] = $this->normalize_sorting_trigger( is_array( $list ) ? $list : array() );
		}

		return $out;
	}

	/**
	 * Migrate the pre-rename sorting trigger value.
	 *
	 * Sorting used to reuse the same 'bought_together' value as the unrelated
	 * filter trigger of the same name; sorting entries now use
	 * 'bought_together_frequency' instead. Normalizing here (rather than only
	 * in the admin REST layer) keeps the storefront correct for any list that
	 * hasn't been re-saved through the builder yet.
	 *
	 * @param array $list_item A single recommendedLists entry.
	 * @return array
	 */
	private function normalize_sorting_trigger( $list_item ) {
		if ( ! isset( $list_item['sorting'] ) || ! is_array( $list_item['sorting'] ) ) {
			return $list_item;
		}

		foreach ( $list_item['sorting'] as $i => $rule ) {
			if ( is_array( $rule ) && isset( $rule['triggerType'] ) && 'bought_together' === $rule['triggerType'] ) {
				$list_item['sorting'][ $i ]['triggerType'] = 'bought_together_frequency';
			}
		}

		return $list_item;
	}
}
