<?php

namespace Barn2\Plugin\WC_Product_Table\Data;

use Barn2\Plugin\WC_Product_Table\Util\Util;

/**
 * Gets the data for a custom field column.
 *
 * @package   Barn2\woocommerce-product-table
 * @author    Barn2 Plugins <support@barn2.com>
 * @license   GPL-3.0
 * @copyright Barn2 Media Ltd
 */
class Product_Custom_Field extends Abstract_Product_Data {

	private $field;
	private $image_size;
	private $date_format;
	private $is_date;
	private $acf_field_object;

	public function __construct( $product, $field, $links = '', $image_size = '', $date_format = '', $column_type = [] ) {
		parent::__construct( $product, $links );

		$this->field = $field;

		if ( $this->is_ept_custom_field( $this->field ) ) {
			$this->field = 'product_' . $this->field;
		}

		$this->image_size  = $image_size ? $image_size : 'thumbnail';
		$this->date_format = $date_format;
		$this->is_date     = in_array( 'cf:' . $this->field . '::date', $column_type, true );

		// We use the parent product (if any) for retrieving the ACF field.
		$this->acf_field_object = Util::get_acf_field_object( $this->field, $this->get_parent_product_id() );
	}

	public function get_data() {
		$is_acf_date_picker = false;
		$product_id         = $this->get_product_id();
		$parent_id          = $this->get_parent_product_id();

		if ( $this->acf_field_object ) {
			// ACF custom field.
			$is_acf_date_picker = in_array( $this->acf_field_object['type'], [ 'date_picker', 'date_time_picker' ], true );

			// We use parent ID here as custom fields can't be applied to variations with ACF.
			$cf_value = $this->get_acf_value( $this->acf_field_object, $parent_id );
		} else {
			// 'Regular' custom field.
			$cf_value = get_post_meta( $product_id, $this->field, false );

			if ( $product_id !== $parent_id ) {
				// Product is a variation, so fetch custom field for parent if the child value is empty.
				if ( ( is_array( $cf_value ) && empty( $cf_value ) ) || null === $cf_value || false === $cf_value ) {
					$cf_value = get_post_meta( $parent_id, $this->field, false );
				}
			}
		}

		// Flatten field.
		$cf_value = array_reduce( (array) $cf_value, [ $this, 'flatten_custom_field' ], '' );

		// Format as date if this is a date custom field and we have a date format.
		if ( $this->is_date && $this->date_format && ! $is_acf_date_picker ) {
			$format = apply_filters( 'wc_product_table_custom_field_stored_date_format', '', $this->field );

			// Convert to timestamp - we don't pass date_format here as that specifies the desired output format, not the input format.
			if ( $timestamp = $this->convert_to_timestamp( $cf_value, $format ) ) {
				// Format date using desired format.
				$cf_value = date_i18n( $this->date_format, $timestamp );
			}
		}

		// Format as link if custom field is a URL - link text defaults to URL, minus the 'http://'
		if ( 0 === strpos( $cf_value, 'http' ) && $link_url = filter_var( $cf_value, FILTER_VALIDATE_URL ) ) {
			$link_text = str_replace( [ 'http://', 'https://' ], '', $cf_value );
			$cf_value  = sprintf(
				'<a href="%1$s">%2$s</a>',
				apply_filters( 'wc_product_table_url_custom_field_link', $link_url, $this->field, $this->product ),
				apply_filters( 'wc_product_table_url_custom_field_text', $link_text, $this->field, $this->product )
			);
		}

		// Filter the result.
		$cf_value = apply_filters( 'wc_product_table_data_custom_field', $cf_value, $this->field, $this->product );
		$cf_value = apply_filters( 'wc_product_table_data_custom_field_' . $this->field, $cf_value, $this->product );

		return $cf_value;
	}

	public function get_sort_data() {
		$result = '';

		if ( $this->is_date ) {
			$date   = get_post_meta( $this->get_product_id(), $this->field, true ) !== '' ? get_post_meta( $this->get_product_id(), $this->field, true ) : get_post_meta( $this->get_parent_product_id(), $this->field, true );
			$format = apply_filters( 'wc_product_table_custom_field_stored_date_format', '', $this->field );

			// Format the hidden date column for sorting
			if ( $timestamp = $this->convert_to_timestamp( $date, $format ) ) {
				$result = $timestamp;
			} else {
				// We need to return non-empty string to ensure all CF dates have a sort value.
				$result = '0';
			}
		}

		return apply_filters( 'wc_product_table_data_sort_custom_field_' . $this->field, $result, $this->product );
	}

	private function get_acf_value( $field_obj, $product_id = false ) {
		if ( ! $field_obj || ! isset( $field_obj['value'] ) || '' === $field_obj['value'] || 'null' === $field_obj['value'] || empty( $field_obj['type'] ) ) {
			return '';
		}

		$cf_value = $field_obj['value'];

		switch ( $field_obj['type'] ) {
			case 'text':
			case 'number':
			case 'email':
			case 'password':
			case 'color_picker':
			case 'textarea':
			case 'wysiwyg':
			case 'google_map':
				$cf_value = get_field( $field_obj['name'], $product_id, true );
				break;
			case 'date_picker':
			case 'date_time_picker':
				if ( $timestamp = $this->convert_to_timestamp( $cf_value ) ) {
					// Use 'date_format' option if specified, otherwise use the 'return format' for the date field
					$date_format = $this->date_format ?: $field_obj['return_format'];
					$cf_value    = date_i18n( $date_format, $timestamp );
				}
				break;
			case 'time_picker':
				if ( $timestamp = $this->convert_to_timestamp( $cf_value ) ) {
					$cf_value = date_i18n( $field_obj['return_format'], $timestamp );
				}
				break;
			case 'radio':
				if ( ! empty( $field_obj['choices'] ) && ( is_int( $cf_value ) || is_string( $cf_value ) ) && isset( $field_obj['choices'][ $cf_value ] ) ) {
					$cf_value = $field_obj['choices'][ $cf_value ];
				}
				break;
			case 'select':
			case 'checkbox':
				if ( ! empty( $field_obj['choices'] ) && ( is_string( $cf_value ) || is_int( $cf_value ) || is_array( $cf_value ) ) ) {
					$labels = [];

					foreach ( (array) $cf_value as $value ) {
						if ( isset( $field_obj['choices'][ $value ] ) ) {
							$labels[] = $field_obj['choices'][ $value ];
						} else {
							$labels[] = $value;
						}
					}
					$cf_value = $labels;
				}
				break;
			case 'true_false':
				$cf_value = $cf_value ? __( 'True', 'woocommerce-product-table' ) : __( 'False', 'woocommerce-product-table' );
				break;
			case 'file':
				$cf_value = wp_get_attachment_link( $cf_value, $this->image_size, false, true );
				break;
			case 'image':
				$cf_value = wp_get_attachment_link( $cf_value, $this->image_size );
				break;
			case 'page_link':
			case 'post_object':
			case 'relationship':
				$titles = [];

				foreach ( (array) $cf_value as $post_id ) {
					if ( array_intersect( [ 'all', 'name' ], $this->links ) ) {
						$titles[] = sprintf( '<a href="%1$s">%2$s</a>', get_permalink( $post_id ), get_the_title( $post_id ) );
					} else {
						$titles[] = get_the_title( $post_id );
					}
				}
				$cf_value = $titles;
				break;
			case 'taxonomy':
				$term_links = [];
				foreach ( (array) $cf_value as $term_id ) {
					if ( $term = get_term_by( 'id', $term_id, $field_obj['taxonomy'] ) ) {
						if ( array_intersect( [ 'all', 'terms' ], $this->links ) ) {
							$term_links[] = sprintf( '<a href="%1$s" rel="tag">%2$s</a>', esc_url( get_term_link( $term_id, $field_obj['taxonomy'] ) ), $term->name );
						} else {
							$term_links[] = $term->name;
						}
					}
				}
				$cf_value = $term_links;
				break;
			case 'user':
				$users = [];
				foreach ( (array) $cf_value as $user_id ) {
					if ( array_intersect( [ 'all', 'author' ], $this->links ) ) {
						$users[] = sprintf(
							'<a href="%1$s" rel="author">%2$s</a>',
							esc_url( get_author_posts_url( $user_id ) ),
							get_the_author_meta( 'display_name', $user_id )
						);
					} else {
						$users[] = get_the_author_meta( 'display_name', $user_id );
					}
				}
				$cf_value = $users;
				break;
			case 'repeater':
				$repeater_value = [];

				if ( have_rows( $field_obj['name'], $product_id ) ) {
					while ( have_rows( $field_obj['name'], $product_id ) ) {
						the_row();

						foreach ( $field_obj['sub_fields'] as $sub_field ) {
							$sub_field_value  = $this->get_acf_value( get_sub_field_object( $sub_field['name'], false ), $product_id );
							$repeater_value[] = apply_filters( 'wc_product_table_acf_sub_field_value', $sub_field_value, $sub_field['name'], $field_obj['name'], $product_id );
						}
					}
				}
				$cf_value = apply_filters( 'wc_product_table_acf_repeater_field_value', $repeater_value );
				break;
			// @todo: Other layout field types?
		}

		return apply_filters( 'wc_product_table_acf_value', $cf_value, $field_obj, $product_id );
	}

	private function convert_to_timestamp( $date, $format = '' ) {
		if ( ! $date ) {
			return false;
		}

		if ( Util::is_european_date_format( $format ) || apply_filters( 'wc_product_table_custom_field_is_eu_au_date', false, $this->field ) ) {
			$date = str_replace( '/', '-', $date );
		}

		return Util::strtotime( $date );
	}

	private function flatten_custom_field( $carry, $item ) {
		if ( is_array( $item ) ) {
			if ( $carry ) {
				$carry .= parent::get_separator( 'custom_field_row' );
			}
			$carry .= array_reduce( $item, [ $this, 'flatten_custom_field' ], '' );
		} elseif ( '' !== $item && false !== $item ) {
			if ( $carry ) {
				$carry .= parent::get_separator( 'custom_field' );
			}
			$carry .= $item;
		}
		return $carry;
	}

	/**
	 * Check if a given meta key is an EPT custom field for a specific post type
	 *
	 * @param string $meta_key The meta key to check
	 * @return bool True if the meta key is an EPT custom field, false otherwise
	 */
	public function is_ept_custom_field( $meta_key ) {
		// Check if the EPT Util class exists
		if ( ! class_exists( '\Barn2\Plugin\Easy_Post_Types_Fields\Util' ) ) {
			return false;
		}

		// Get all custom fields for the post type
		$custom_fields = \Barn2\Plugin\Easy_Post_Types_Fields\Util::get_custom_fields( 'product' );

		if ( empty( $custom_fields ) ) {
			return false;
		}

		// Check if the meta key exists in any of the custom fields
		foreach ( $custom_fields as $field ) {
			if ( isset( $field['slug'] ) && $field['slug'] === $meta_key ) {
				return true;
			}
		}

		return false;
	}
}
