<?php
declare( strict_types=1 );

namespace FiboFilters\Integrations\Plugins;

use FiboFilters\Filters\SourceTypes\CustomField;

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

/**
 * Class AdvancedCustomFields
 *
 * Plugin Name: Advanced Custom Fields
 * Plugin URI: https://www.advancedcustomfields.com/
 * Tested versions: 6.2.10
 */
class AdvancedCustomFields extends AbstractPlugin {
	public function init(): void {
		add_filter( 'fibofilters/filters/prepared_sources', [ $this, 'add_sources' ], 2, 2 );
		add_filter( 'fibofilters/indexer/filters_source_query/value_label', [ $this, 'value_label' ], 5, 3 );

		add_action( 'fibofilters/indexer/filters_source_query/unparsed_row/language_switch', [ $this, 'reset_acf_fields_store' ] );
	}

	public function add_sources( $sources, $woocommerce_helper ): array {
		foreach ( $this->get_fields() as $field ) {
			$data = [
				'label'                 => $field['label_long'],
				'value'                 => 'acf_' . $field['key'],
				'sourceType'            => 'advanced_custom_field',
				'rawValue'              => $field['key'],
				'allowedTypes'          => [
					'radio',
					'select',
					'checkboxes',
					'buttons',
				],
				'overwrittenAttributes' => [
					'label' => $field['label_short'],
				],
				'orderByTermOrder'      => false,
				'userInputType'         => 'default',
			];

			// Overwriting some fields depending on the field type.
			if ( $field['type'] === 'true_false' ) {
				$data['allowedTypes'] = [
					'toggle',
				];
			}

			if ( $field['type'] === 'number' || $field['type'] === 'range' ) {
				$data['allowedTypes'][] = 'range';
			}

			if ( $field['type'] === 'color_picker' ) {
				$data['allowedTypes'] = [ 'color' ];
			}

			$sources[] = new CustomField(
				$woocommerce_helper,
				$data,
				false,
				false
			);
		}

		return $sources;
	}

	/**
	 * Get all ACF fields related to products
	 */
	private function get_fields(): array {
		$fields = [];

		add_action( 'pre_get_posts', [ $this, 'disable_wpml' ] );
		$field_groups = acf_get_field_groups();
		remove_action( 'pre_get_posts', [ $this, 'disable_wpml' ] );

		foreach ( $field_groups as $group ) {
			if ( empty( $group ) || ! is_array( $group ) || ! $group['active'] || ! $this->is_group_related_to_product( $group ) ) {
				continue;
			}

			$acf_fields = acf_get_fields( $group );
			if ( empty( $acf_fields ) ) {
				continue;
			}

			$fields = array_merge( $fields, $this->prepare_fields( $acf_fields, $group ) );
		}

		return $fields;
	}

	/**
	 * Prepare list of ACF fields that can be indexed
	 *
	 * @param array  $acf_fields Group of ACF fields.
	 * @param array  $group Parent group.
	 * @param string $label Label.
	 * @param string $key Key.
	 */
	private function prepare_fields( array $acf_fields, array $group, string $label = '', string $key = '' ): array {
		$fields = [];

		if ( empty( $label ) ) {
			$label = '[ACF] ' . $group['title'];
		}

		foreach ( $acf_fields as $acf_field ) {
			if ( ! in_array( $acf_field['type'], $this->get_allowed_field_types(), true ) ) {
				continue;
			}

			if ( empty( $acf_field['name'] ) ) {
				continue;
			}

			$fields[] = [
				'label_long'  => $label . ' → ' . $acf_field['label'],
				'label_short' => $acf_field['label'],
				'key'         => $key . $acf_field['name'],
				'type'        => $acf_field['type'],
				'acf_field'   => $acf_field,
			];
		}

		return $fields;
	}

	/**
	 * Determine value label for ACF field
	 *
	 * @param string $label Label.
	 * @param string $value Value.
	 * @param string $col_name Column.
	 */
	public function value_label( string $label, string $value, string $col_name ): string {
		if ( strpos( $col_name, 'acf_' ) === 0 && strpos( $label, 'field_' ) === 0 ) {
			$field = get_field_object( $label );
			if (
				! empty( $field['type'] ) &&
				in_array( $field['type'], [ 'button_group', 'checkbox', 'radio', 'select' ], true ) &&
				isset( $field['choices'][ $value ] )
			) {
				$label = $field['choices'][ $value ];
			} elseif ( ! empty( $field['type'] ) && $field['type'] === 'true_false' ) {
				$label = ! empty( $field['message'] ) ? $field['message'] : $field['label'];
			} elseif (
				! empty( $field['type'] ) &&
				in_array( $field['type'], [ 'color_picker', 'number' ], true )
			) {
				$label = $value;
			}
		}

		return $label;
	}

	/**
	 * Check if group is related to product
	 *
	 * The group may have different conditions, but we are only checking the relation to the product post type.
	 *
	 * @param array $group Group of fields.
	 */
	private function is_group_related_to_product( array $group ): bool {
		if ( empty( $group ) || empty( $group['location'] ) ) {
			return false;
		}

		foreach ( $group['location'] as $rule_group ) {
			if ( empty( $rule_group ) ) {
				continue;
			}

			foreach ( $rule_group as $rule ) {
				if ( $rule['operator'] === '==' && $rule['param'] === 'post_type' && $rule['value'] === 'product' ) {
					return true;
				}
			}
		}

		return false;
	}

	/**
	 * We want to get fields in all languages
	 *
	 * @param \WP_Query $query Query.
	 */
	public function disable_wpml( $query ): void {
		$query->set( 'suppress_filters', true );
		$query->set( 'lang', '' );
	}

	/**
	 * Reset ACF fields store
	 *
	 * This is needed to ensure that the ACF fields are reloaded when the language is switched.
	 * Otherwise, the fields may not be available in the new language.
	 */
	public function reset_acf_fields_store() {
		if ( ! function_exists( 'acf_get_store' ) ) {
			return;
		}

		$store = acf_get_store( 'fields' );
		if ( is_a( $store, 'ACF_Data' ) ) {
			$store->reset();
		}
	}

	/**
	 * Get allowed field types
	 *
	 * @return string[]
	 */
	private function get_allowed_field_types(): array {
		$types = [
			'button_group',
			'checkbox',
			'number',
			'radio',
			'range',
			'select',
			'true_false',
			'number',
			'color_picker'
		];

		return apply_filters( 'fibofilters/integrations/plugins/acf/allowed_field_types', $types );
	}
}
