<?php
/**
 * Formidable field entitlement policy.
 *
 * @package EntryFoundry
 */

namespace EntryFoundry\Formidable;

/**
 * Centralizes the server-side Lite/Pro field boundary.
 */
final class FormidableFieldPolicy {

	/**
	 * Formidable data boundary.
	 *
	 * @var FormidableData
	 */
	private $data;

	/**
	 * Constructor.
	 *
	 * @param FormidableData $data Formidable data boundary.
	 */
	public function __construct( FormidableData $data ) {
		$this->data = $data;
	}

	/**
	 * Return Pro field IDs referenced by a template while Pro is inactive.
	 *
	 * @param array<string, mixed> $template Template document.
	 * @return array<int, int>
	 */
	public function get_restricted_field_ids( array $template ): array {
		if ( function_exists( 'entryfoundry_is_pro' ) && \entryfoundry_is_pro() ) {
			return array();
		}

		$form_id = isset( $template['source']['form_id'] ) ? (int) $template['source']['form_id'] : 0;
		if ( $form_id < 1 ) {
			return array();
		}

		$pro_field_ids = array();
		foreach ( $this->data->get_fields( $form_id ) as $field ) {
			if ( ! empty( $field['is_pro'] ) ) {
				$pro_field_ids[ (int) $field['id'] ] = true;
			}
		}

		$referenced_ids = array();
		$this->collect_field_ids( $template['elements'] ?? array(), $referenced_ids );

		return array_values( array_map( 'intval', array_keys( array_intersect_key( $pro_field_ids, $referenced_ids ) ) ) );
	}

	/**
	 * Recursively collect field_id values from elements, tables, and extensions.
	 *
	 * @param mixed            $value     Template fragment.
	 * @param array<int, bool> $field_ids Collected IDs.
	 * @return void
	 */
	private function collect_field_ids( $value, array &$field_ids ): void {
		if ( ! is_array( $value ) ) {
			return;
		}

		if ( isset( $value['field_id'] ) && is_numeric( $value['field_id'] ) ) {
			$field_ids[ (int) $value['field_id'] ] = true;
		}

		foreach ( $value as $child ) {
			$this->collect_field_ids( $child, $field_ids );
		}
	}
}
