<?php
/**
 * ACFData trait.
 *
 * This trait handles Advanced Custom Fields (ACF) data retrieval and
 * formatting.
 *
 * @package Etch\Traits
 */

declare(strict_types=1);

namespace Etch\Traits;

use WP_Post;

trait ACFData {
	use DynamicDataBases;


	/**
	 * Retrieves and formats ACF fields for a post.
	 *
	 * @param WP_Post $post The post object.
	 * @return array<string, mixed> ACF field values with proper formatting.
	 */
	protected function get_acf_data( WP_Post $post ): array {
		if ( ! function_exists( '\get_fields' ) ) {
			// ACF is not active; log for debugging
			error_log( 'ACF plugin is not installed or active.' );
			return array();
		}

		$acf_fields = \get_fields( $post->ID );

		if ( ! $acf_fields || ! is_array( $acf_fields ) ) {
			return array();
		}

		$formatted_fields = array();
		foreach ( $acf_fields as $key => $value ) {
			$formatted_fields[ $key ] = $this->
				format_acf_field( $key, $value, $post->ID );
		}

		return $formatted_fields;
	}

	/**
	 * Formats an ACF field based on its type.
	 *
	 * @param string $key The field key.
	 * @param mixed  $value The field value.
	 * @param int    $post_id The post ID.
	 * @return mixed The formatted field value.
	 */
	protected function format_acf_field(
		string $key,
		$value,
		int $post_id
	) {
		if ( empty( $value ) ) {
			return $value;
		}

		if ( ! function_exists( '\get_field_object' ) ) {
			return $value;
		}

		$field_object = \get_field_object( $key, $post_id );

		if ( ! $field_object || ! isset( $field_object['type'] ) ) {
			return $value;
		}

		return $this->format_field_by_type( $field_object['type'], $value, $field_object, $post_id );
	}

	/**
	 * Formats a field value based on its type using a centralized switch statement.
	 *
	 * @param string               $field_type The field type.
	 * @param mixed                $value The field value.
	 * @param array<string, mixed> $field_object The field object from ACF.
	 * @param int                  $post_id The post ID.
	 * @return mixed The formatted field value.
	 */
	protected function format_field_by_type( string $field_type, $value, array $field_object, int $post_id ) {
		switch ( $field_type ) {
			case 'image':
				return $this->format_image_field( $value );

			case 'link':
				return $this->format_link_field( $value );

			case 'repeater':
				return $this->format_repeater_field( $value, $field_object, $post_id );

			// TODO: Probably some extra handling in the future
			case 'select':
			case 'checkbox':
				return $value;

			default:
				return $value;
		}
	}

	/**
	 * Formats an image field to provide additional properties.
	 *
	 * @param mixed $value The image field value.
	 * @return array<string, mixed> Formatted image data.
	 */
	protected function format_image_field( $value ): array {
		// Handle ACF image array with ID
		if ( is_array( $value ) && isset( $value['ID'] ) ) {
			return $this->get_base_image_data( $value['ID'] );
		}

		// Handle attachment ID
		if ( is_numeric( $value ) ) {
			return $this->get_base_image_data( (int) $value );
		}

		// Handle image URL
		if ( is_string( $value ) && ! empty( $value ) ) {
			return $this->get_base_image_data( $value );
		}

		// Return empty array for invalid/empty values
		return array();
	}

	/**
	 * Formats a link field.
	 *
	 * @param mixed $value The link field value.
	 * @return array<string, string> Formatted link data.
	 */
	protected function format_link_field( $value ): array {
		if ( empty( $value ) ) {
			return array(
				'url' => '',
				'title' => '',
				'target' => '',
			);
		}

		if ( is_string( $value ) ) {
			return array(
				'url' => $value,
				'title' => '',
				'target' => '',
			);
		}

		if ( is_array( $value ) ) {
			return array(
				'url' => isset( $value['url'] ) ? $value['url'] : '',
				'title' => isset( $value['title'] ) ? $value['title'] : '',
				'target' => isset( $value['target'] ) ? $value['target'] : '',
			);
		}

		return array(
			'url' => '',
			'title' => '',
			'target' => '',
		);
	}

	/**
	 * Formats a repeater field by processing each row and its sub-fields.
	 *
	 * @param mixed                $value The repeater field value.
	 * @param array<string, mixed> $field_object The field object from ACF.
	 * @param int                  $post_id The post ID.
	 * @return array<int, array<string, mixed>> Formatted repeater data.
	 */
	protected function format_repeater_field( $value, array $field_object, int $post_id ): array {
		if ( ! is_array( $value ) || empty( $value ) ) {
			return array();
		}

		$formatted_rows = array();

		foreach ( $value as $row_index => $row_data ) {
			if ( ! is_array( $row_data ) ) {
				continue;
			}

			$formatted_row = array();

			foreach ( $row_data as $sub_field_key => $sub_field_value ) {
				// Format each sub-field recursively
				$formatted_row[ $sub_field_key ] = $this->format_repeater_sub_field(
					$sub_field_key,
					$sub_field_value,
					$field_object,
					$post_id,
					$row_index
				);
			}

			$formatted_rows[] = $formatted_row;
		}

		return $formatted_rows;
	}

	/**
	 * Formats a sub-field within a repeater field.
	 *
	 * @param string               $sub_field_key The sub-field key.
	 * @param mixed                $sub_field_value The sub-field value.
	 * @param array<string, mixed> $parent_field_object The parent repeater field object.
	 * @param int                  $post_id The post ID.
	 * @param int                  $row_index The row index within the repeater.
	 * @return mixed The formatted sub-field value.
	 */
	protected function format_repeater_sub_field(
		string $sub_field_key,
		$sub_field_value,
		array $parent_field_object,
		int $post_id,
		int $row_index
	) {
		if ( empty( $sub_field_value ) ) {
			return $sub_field_value;
		}

		if ( ! function_exists( '\get_field_object' ) ) {
			return $sub_field_value;
		}

		// Try to get the sub-field object from the parent repeater field
		$sub_field_object = null;
		if ( isset( $parent_field_object['sub_fields'] ) && is_array( $parent_field_object['sub_fields'] ) ) {
			foreach ( $parent_field_object['sub_fields'] as $sub_field ) {
				if ( isset( $sub_field['name'] ) && $sub_field['name'] === $sub_field_key ) {
					$sub_field_object = $sub_field;
					break;
				}
			}
		}

		// Fallback: try to get field object directly (this might work in some cases)
		if ( ! $sub_field_object ) {
			$sub_field_object = \get_field_object( $sub_field_key, $post_id );
		}

		if ( ! $sub_field_object || ! isset( $sub_field_object['type'] ) ) {
			return $sub_field_value;
		}

		// Format based on sub-field type using the centralized helper
		return $this->format_field_by_type( $sub_field_object['type'], $sub_field_value, $sub_field_object, $post_id );
	}

	/**
	 * Retrieves ACF field types for a post.
	 *
	 * @param WP_Post $post The post object.
	 * @return array<string, string> ACF field names and their types.
	 */
	protected function get_acf_field_types( WP_Post $post ): array {
		if ( ! function_exists( '\get_fields' ) ) {
			// ACF is not active
			return array();
		}

		$acf_fields = \get_fields( $post->ID );

		if ( ! $acf_fields || ! is_array( $acf_fields ) ) {
			return array();
		}

		if ( ! function_exists( '\get_field_object' ) ) {
			return array();
		}

		$field_types = array();
		foreach ( array_keys( $acf_fields ) as $key ) {
			$field_object = \get_field_object( $key, $post->ID );
			if ( $field_object && isset( $field_object['type'] ) ) {
				$field_types[ $key ] = (string) $field_object['type'];
			}
		}

		return $field_types;
	}
}
