<?php
if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

function wpo_wcpdf_templates_get_table_headers( $document ) {
	$column_settings = WPO_WCPDF_Templates()->settings->get_settings( $document->get_type(), 'columns', $document );
	$order_discount  = $document->get_order_discount( 'total', 'incl' );
	$taxes           = $document->get_order_taxes();

	// mark first and last column
	if ( ! empty( $column_settings ) ) {
		end( $column_settings );
		$column_settings[ key( $column_settings ) ]['position'] = 'last';
		reset( $column_settings );
		$column_settings[ key( $column_settings ) ]['position'] = 'first';
	}

	$headers = array();

	foreach ( $column_settings as $column_key => $column_setting) {
		if ( ! $order_discount && isset( $column_setting['only_discounted'] ) ) {
			continue;
		}
		
		// vat split column
		if ( 'vat' === $column_setting['type'] && isset( $column_setting['split'] ) && ! empty( $taxes ) ) {			
			foreach ( $taxes as $tax ) {
				$title      = $tax['label'] . ' (' . $tax['rate'] . ')';				
				$new_column = array(
					'split' => '1',
					'title' => apply_filters( 'wpo_wcpdf_vat_split_column_title', $title, $tax ),
					'class' => 'vat-split',
					'type'  => 'vat',
				);
				$new_column_key             = $column_key . '_' . $tax['rate_id'];
				$headers[ $new_column_key ] = $column_setting + $new_column + WPO_WCPDF_Templates()->main->get_order_details_header( $new_column, $document );
			}
		
		// default column
		} else {
			$headers[ $column_key ] = $column_setting + WPO_WCPDF_Templates()->main->get_order_details_header( $column_setting, $document );
		}
	}

	return apply_filters( 'wpo_wcpdf_templates_table_headers', $headers, $document->get_type(), $document );
}

function wpo_wcpdf_templates_get_table_body( $document ) {
	$column_settings = WPO_WCPDF_Templates()->settings->get_settings( $document->get_type(), 'columns', $document );
	$order_discount  = $document->get_order_discount( 'total', 'incl' );
	$taxes           = $document->get_order_taxes();

	// mark first and last column
	if ( ! empty( $column_settings ) ) {
		end( $column_settings );
		$column_settings[ key( $column_settings ) ]['position'] = 'last';
		reset( $column_settings );
		$column_settings[ key( $column_settings ) ]['position'] = 'first';
	}
	
	$body  = array();
	$items = $document->get_order_items();
	
	if ( sizeof( $items ) > 0 ) {
		foreach ( $column_settings as $column_key => $column_setting ) {
			$line_number = 1;
			foreach ( $items as $item_id => $item ) {
				if ( ! $order_discount && isset( $column_setting['only_discounted'] ) ) {
					continue;
				}

				$column_setting['line_number'] = $line_number;
				
				// vat split column	
				if ( 'vat' === $column_setting['type'] && isset( $column_setting['split'] ) && ! empty( $taxes ) ) {
					$item_taxes                   = $item['item']->get_taxes();
					$item_subtotal_taxes          = isset( $item_taxes['subtotal'] ) ? $item_taxes['subtotal'] : array();
					$filtered_item_subtotal_taxes = array_filter( $item_subtotal_taxes );
					$multiple                     = ! empty( $filtered_item_subtotal_taxes ) && count( $filtered_item_subtotal_taxes ) > 1;
					
					// loop order taxes to add item split ones
					foreach ( $taxes as $tax ) {
						// add split tax
						$split = array();
						
						foreach ( $item_taxes as $item_tax_type => $item_tax_values ) {
							$value                   = ! empty( $item_tax_values[ $tax['rate_id'] ] ) ? $item_tax_values[ $tax['rate_id'] ] : 0;
							$split[ $item_tax_type ] = floatval( $value );
						}
						
						if ( ! isset( $split['subtotal'] ) && isset( $split['total'] ) ) {
							$split['subtotal'] = $split['total'];
						}
						
						// the item has multiple taxes?
						$split['multiple'] = $multiple;
						$split['tax_rate'] = $tax['rate'];
						
						// add split discount
						if ( is_callable( array( $item['item'], 'get_subtotal' ) ) && is_callable( array( $item['item'], 'get_total' ) ) ) {
							$split['discount'] = floatval( $item['item']->get_subtotal() - $item['item']->get_total() );
						} else {
							$split['discount'] = 0;
						}
						$split['discount_tax'] = floatval( $item['item']['line_subtotal_tax'] - $item['item']['line_tax'] );
						
						// add column
						$new_column = array(
							'type'          => $column_setting['type'],
							'split'         => $split,
							'dash_for_zero' => isset( $column_setting['dash_for_zero'] ),
							'label'         => $column_setting['label'],
							'price_type'    => $column_setting['price_type'],
							'discount'      => $column_setting['discount'],
						);
						
						$new_column_key                      = $column_key . '_' . $tax['rate_id'];
						$body[ $item_id ][ $new_column_key ] = $new_column + WPO_WCPDF_Templates()->main->get_order_details_data( $new_column, $item, $document );
					}
				
				// default column
				} else {
					$body[ $item_id ][ $column_key ] = $column_setting + WPO_WCPDF_Templates()->main->get_order_details_data( $column_setting, $item, $document );
				}
				
				$line_number++;
			}
		}
	}

	return apply_filters( 'wpo_wcpdf_templates_table_body', $body, $document->get_type(), $document );
}

function wpo_wcpdf_templates_get_totals( $document ) {
	$total_settings = WPO_WCPDF_Templates()->settings->get_settings( $document->get_type(), 'totals', $document );
	$totals_data = WPO_WCPDF_Templates()->main->get_totals_table_data( $total_settings, $document );

	return apply_filters( 'wpo_wcpdf_templates_totals', $totals_data, $document->get_type(), $document );
}

function wpo_wcpdf_templates_get_footer_settings( $document, $default_height = '5cm' ) {
	$footer_height = str_replace( ' ', '', WPO_WCPDF_Templates()->settings->get_footer_height() );
	if ( empty( $footer_height ) ) {
		$footer_height = $default_height;
	}

	// calculate bottom page margin
	$page_bottom = floatval($footer_height);

	// convert to cm
	if (strpos($footer_height,'in') !== false) {
		$page_bottom = $page_bottom * 2.54;
	} elseif (strpos($footer_height,'mm') !== false) {
		$page_bottom = $page_bottom / 10;
	}

	// set limit cap in cm
	$limit_cap = apply_filters( 'wpo_wcpdf_templates_footer_height_limit', 10 );
	if( $page_bottom > $limit_cap ) {
		$page_bottom = $limit_cap;
	}

	// footer height
	$footer_height = $page_bottom.'cm';

	// add 1 + cm
	$page_bottom   = ($page_bottom + 1).'cm';

	return compact( 'footer_height', 'page_bottom' );
}

/**
 * Get the shipping zones.
 *
 * @return array
 */
function wpo_wcpdf_templates_get_shipping_zones(): array {
	// Shipping methods extracted from shipping zones and default zone processing.
	$zones_with_default    = \WC_Shipping_Zones::get_zones();
	$zones_with_default[0] = \WC_Shipping_Zones::get_zone( 0 ); // add the default zone at index 0

	return $zones_with_default;
}

/**
 * Helper function to generate shipping method title with legacy tag if applicable.
 *
 * @param \WC_Shipping_Method $shipping_method
 *
 * @return string
 */
function wpo_wcpdf_templates_get_shipping_method_title( \WC_Shipping_Method $shipping_method ): string {
	$title = '';

	if ( is_callable( array( $shipping_method, 'get_title' ) ) ) {
		$title = $shipping_method->get_title();
	}

	if ( empty( $title ) && is_callable( array( $shipping_method, 'get_method_title' ) ) ) {
		$title = $shipping_method->get_method_title();
	}

	if ( 'local_pickup' === $shipping_method->id && function_exists( 'wpo_wcpdf_checkout_is_block' ) && wpo_wcpdf_checkout_is_block() ) {
		$title .= ' (' . __( 'legacy', 'wpo_wcpdf_templates' ) . ')';
	}

	return apply_filters( 'wpo_wcpdf_templates_get_shipping_method_title', $title, $shipping_method );
}

/**
 * Helper function to generate the shipping method label.
 *
 * @param string $suffix
 * @param string $title
 * @param string $id
 *
 * @return string
 */
function wpo_wcpdf_templates_generate_shipping_method_label( string $suffix, string $title, string $id = '' ): string {
	$label = sprintf( '%s - %s', $title, $suffix );

	if ( '' === $id ) {
		return $label;
	}

	return sprintf( '%s (#%s)', $label, $id );
}

/**
 * Gets all order shipping methods instance IDs.
 * In case the shipping method is a default one, it will return the shipping method ID.
 * 
 * @param \WC_Abstract_Order $order
 *
 * @return array
 */
function wpo_wcpdf_templates_get_order_shipping_methods( \WC_Abstract_Order $order ): array {
	$shipping_methods = array();

	// Map order shipping methods
	foreach ( $order->get_shipping_methods() as $shipping_item ) {
		$method_id    = is_callable( array( $shipping_item, 'get_method_id' ) ) ? $shipping_item->get_method_id() : '';
		$instance_id  = is_callable( array( $shipping_item, 'get_instance_id' ) ) ? $shipping_item->get_instance_id() : '';
		$found        = false;

		foreach ( wpo_wcpdf_templates_get_all_shipping_methods_as_options() as $key => $title ) {
			if ( preg_match( '/:\d+$/', $key ) ) {
				$key_arr = explode( ':', $key );

				if (
					$key_arr[0] === $method_id &&
					is_numeric( $instance_id ) &&
					absint( $key_arr[1] ) === absint( $instance_id )
				) {
					$shipping_methods[] = $key;
					$found              = true;
					break;
				}
			}
		}

		if ( ! $found ) {
			$shipping_methods[] = $method_id . ':' . $instance_id;
		}
	}

	return apply_filters( 'wpo_wcpdf_templates_get_order_shipping_methods', $shipping_methods, $order );
}

/**
 * Gets all available pickup locations for the checkout block.
 *
 * @return array
 */
function wpo_wcpdf_templates_get_checkout_block_pickup_locations(): array {
	$pickup_locations          = array();
	$pickup_locations_settings = class_exists( '\\Automattic\\WooCommerce\\StoreApi\\Utilities\\LocalPickupUtils' ) ? \Automattic\WooCommerce\StoreApi\Utilities\LocalPickupUtils::get_local_pickup_settings() : array();
	$pickup_locations_enabled  = isset( $pickup_locations_settings['enabled'] ) ? $pickup_locations_settings['enabled'] : false;
	$pickup_locations_title	   = isset( $pickup_locations_settings['title'] ) ? $pickup_locations_settings['title'] : __( 'Pickup Locations', 'wpo_wcpdf_templates' );

	if ( $pickup_locations_enabled && class_exists( '\\Automattic\\WooCommerce\\Blocks\\Shipping\\PickupLocation' ) ) {
		$_pickup_locations = get_option( 'pickup_location_pickup_locations', array() );

		foreach ( $_pickup_locations as $index => $location ) {
			if ( wc_string_to_bool( $location['enabled'] ) ) {
				$pickup_location              = new \Automattic\WooCommerce\Blocks\Shipping\PickupLocation();
				$pickup_location->id          = 'pickup_location';
				$pickup_location->instance_id = $index;
				$pickup_location->title       = sprintf( '%s (%s)', $pickup_locations_title, $location['name'] );

				$pickup_locations[ 'pickup_location:' . $index ] = $pickup_location;
			}
		}
	}

	return apply_filters( 'wpo_wcpdf_templates_get_checkout_block_pickup_locations', $pickup_locations, $pickup_locations_settings );
}

/**
 * Get all shipping zone methods.
 *
 * @return array
 */
function wpo_wcpdf_get_all_shipping_zone_methods(): array {
	$shipping_zone_methods = array();

	// Add shipping zone shipping methods
	foreach ( wpo_wcpdf_templates_get_shipping_zones() as $zone_data ) {
		// Check if we're dealing with the default zone or a normal zone
		if ( is_array( $zone_data ) && isset( $zone_data['id'] ) ) {
			$zone = new \WC_Shipping_Zone( $zone_data['id'] );
		} else {
			$zone = $zone_data;
		}

		$shipping_zone_methods += $zone->get_shipping_methods();
	}

	return apply_filters( 'wpo_wcpdf_get_all_shipping_zone_methods', $shipping_zone_methods );
}

/**
 * Get all shipping methods as options.
 *
 * @return array
 */
function wpo_wcpdf_templates_get_all_shipping_methods_as_options(): array {
	$shipping_options = array();

	// Add shipping zone shipping methods
	$shipping_options += wpo_wcpdf_convert_shipping_methods_to_options( wpo_wcpdf_get_all_shipping_zone_methods() );

	// Add checkout block pickup locations
	$shipping_options += wpo_wcpdf_convert_shipping_methods_to_options( wpo_wcpdf_templates_get_checkout_block_pickup_locations() );

	return apply_filters( 'wpo_wcpdf_templates_get_all_shipping_methods_as_options', $shipping_options );
}

/**
 * Convert shipping methods to options.
 *
 * @param array $shipping_methods
 *
 * @return array
 */
function wpo_wcpdf_convert_shipping_methods_to_options( array $shipping_methods ): array {
	if ( empty( $shipping_methods ) ) {
		return array();
	}

	$shipping_options = array();

	foreach ( $shipping_methods as $key => $shipping_method ) {
		if ( ! isset( $shipping_method->id ) || ! isset( $shipping_method->instance_id ) || ! isset( $shipping_method->title ) ) {
			continue;
		}

		if ( ! preg_match( '/:\d+$/', $key ) ) {
			$key = $shipping_method->id . ':' . $shipping_method->instance_id;
		}

		if ( $shipping_method instanceof \WC_Shipping_Method && is_callable( array( $shipping_method, 'get_instance_id' ) ) ) {
			$instance_id              = absint( $shipping_method->get_instance_id() );
			$zone                     = \WC_Shipping_Zones::get_zone_by( 'instance_id', absint( $instance_id ) );
			$zone_id                  = $zone && is_callable( array( $zone, 'get_id' ) ) ? $zone->get_id() : 0;
			$zone_name                = $zone && is_callable( array( $zone, 'get_zone_name' ) ) ? $zone->get_zone_name() : '';
			$shipping_method_title    = wpo_wcpdf_templates_get_shipping_method_title( $shipping_method );
			$suffix                   = ( $zone_id === 0 && empty( $zone_name ) ) ? __( 'Other locations', 'wpo_wcpdf_templates' ) : $zone_name;
			$shipping_options[ $key ] = wpo_wcpdf_templates_generate_shipping_method_label( $suffix, $shipping_method_title, $instance_id );
		}
	}

	return $shipping_options;
}

/**
 * DEPRECATED
 * Determine if the checkout is a block.
 *
 * @return bool
 */
function wpo_wcpdf_templates_checkout_is_block(): bool {
	wcpdf_deprecated_function( 'wpo_wcpdf_templates_checkout_is_block', '2.21.10', 'wpo_wcpdf_checkout_is_block' );
	
	$checkout_page_id = wc_get_page_id( 'checkout' );
	$is_block         = $checkout_page_id && function_exists( 'has_block' ) && has_block( 'woocommerce/checkout', $checkout_page_id );

	if ( ! $is_block ) {
		$is_block = class_exists( 'WC_Blocks_Utils' ) && count( \WC_Blocks_Utils::get_blocks_from_page( 'woocommerce/checkout', 'checkout' ) ) > 0;
	}

	return $is_block;
}

/**
 * Check if any product bundle plugin is activated.
 *
 * @return bool
 */
function wpo_wcpdf_templates_is_product_bundles_plugin_active(): bool {
	$supported_bundle_plugins_slug = apply_filters( 'wpo_wcpdf_templates_supported_product_bundles_plugins', array(
		'woocommerce-product-bundles/woocommerce-product-bundles.php',
		'yith-woocommerce-product-bundles/init.php',
		'woo-product-bundle/wpc-product-bundles.php',
		'woo-product-bundle-premium/wpc-product-bundles.php',
	) );

	foreach ( $supported_bundle_plugins_slug as $supported_bundle_plugin ) {
		if ( is_plugin_active( $supported_bundle_plugin ) ) {
			return true;
		}
	}

	return false;
}


/**
 * Conditionally apply column styles for PDF templates.
 *
 * @param array  $column_data Column data array containing style settings.
 * @param string $target      The target element (header or cells).
 * @return string             The style attribute to be applied.
 */
function wpo_wcpdf_templates_maybe_apply_column_styles( array $column_data, string $target ): string {
	if ( empty( $column_data['style'] ) ) {
		return '';
	}
	
	// Determine if style should be applied
	$apply_style = ! isset( $column_data['style_target'] )
		|| 'both'  === $column_data['style_target']
		|| $target === $column_data['style_target'];
	
	// Sanitize the style value
	$style_value = $apply_style
		? esc_attr( wpo_wcpdf_templates_sanitize_column_style( $column_data['style'] ) )
		: '';
	
	// Return the style attribute only if it should be applied
	return ! empty( $apply_style ) ? ' style="' . $style_value . '"' : '';
}

/**
 * Sanitize CSS for use in table column styles.
 *
 * @param  string $css  Raw user input (e.g. "color: blue; font-size:12px")
 * @return string       Sanitised CSS or an empty string if nothing valid remains
 */
function wpo_wcpdf_templates_sanitize_column_style( string $css ) : string {
	// Strip comments, newlines, tabs, etc.
	$css = preg_replace( '/\/\*.*?\*\//s', '', $css ); // /* … */
	$css = str_replace( array( "\r", "\n", "\t" ), '', $css );
	$css = trim( $css );

	if ( '' === $css ) {
		return '';
	}

	// Allowed properties with validation patterns
	$allowed_styles = array(
		// Colors
		'color'               => '/^(?:#[0-9a-f]{3,8}|(?:rgb|hsl)a?\([0-9%\s,.]+\)|[a-z]+)$/i',
		'background-color'    => '/^(?:#[0-9a-f]{3,8}|(?:rgb|hsl)a?\([0-9%\s,.]+\)|[a-z]+)$/i',

		// Fonts
		'font-size'           => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',
		'font-weight'         => '/^(?:normal|bold|bolder|lighter|\d{3})$/i',
		'font-style'          => '/^(?:normal|italic|oblique)$/i',
		'font-family'         => '/^[a-z0-9,"\-\s]+$/i',
		'line-height'         => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',
		'letter-spacing'      => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',

		// Text alignment and spacing
		'text-align'          => '/^(?:left|right|center|justify)$/i',
		'vertical-align'      => '/^(?:baseline|sub|super|top|middle|bottom|text-bottom)$/i',
		'white-space'         => '/^(?:normal|nowrap|pre|pre-wrap|pre-line)$/i',
		'text-overflow'       => '/^(?:clip|ellipsis)$/i',

		// Box model (padding, margin)
		'padding'             => '/^[0-9.\s]+(?:px|pt|em|rem|%)$/i',
		'padding-top'         => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',
		'padding-right'       => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',
		'padding-bottom'      => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',
		'padding-left'        => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',
		'margin'              => '/^[0-9.\s]+(?:px|pt|em|rem|%)$/i',
		'margin-top'          => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',
		'margin-right'        => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',
		'margin-bottom'       => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',
		'margin-left'         => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',

		// Border
		'border'              => '/^[0-9.]+(?:px|pt|em|rem)?\s+(?:solid|dashed|dotted|double)\s+(?:#[0-9a-f]{3,8}|[a-z]+)$/i',
		'border-radius'       => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',

		// Width and height
		'width'               => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',
		'min-width'           => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',
		'max-width'           => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',
		'height'              => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',
		'min-height'          => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',
		'max-height'          => '/^[0-9.]+(?:px|pt|em|rem|%)$/i',

		// Background settings
		'background'          => '/^(?!.*\burl\s*\([^\)]*\)).+$/i',
		'background-repeat'   => '/^(?:repeat|repeat-x|repeat-y|no-repeat)$/i',
		'background-position' => '/^(?:left|center|right|top|bottom|[0-9.]+(?:px|%)?\s+[0-9.]+(?:px|%)?)$/i',
		'background-size'     => '/^(?:auto|cover|contain|[0-9.]+(?:px|%)?)$/i',

		// Overflow
		'overflow'            => '/^(?:visible|hidden|scroll|auto)$/i',
	);

	// Parse, validate and rebuild
	$safe_parts = array();

	foreach ( explode( ';', $css ) as $declaration ) {
		if ( false === strpos( $declaration, ':' ) ) {
			continue;
		}

		list( $prop, $val ) = array_map( 'trim', explode( ':', $declaration, 2 ) );
		$prop = strtolower( $prop );

		// Skip anything not explicitly allowed
		if ( ! isset( $allowed_styles[ $prop ] ) ) {
			continue;
		}

		// Remove expression() completely
		$val = preg_replace( '/\bexpression\s*\([^\)]*\)/i', '', $val );

		// Remove url() completely
		$val = preg_replace( '/\burl\s*\([^\)]*\)/i', '', $val );


		// Validate the value using the pattern
		if ( preg_match( $allowed_styles[ $prop ], $val ) ) {
			$safe_parts[] = $prop . ': ' . $val;
		}
	}

	// Return a normalized string or empty if nothing survived
	return $safe_parts ? implode( '; ', $safe_parts ) . ';' : '';
}

/**
 * Get country groups
 * 
 * @return array
 */
function wpo_wcpdf_templates_get_country_groups(): array {
	$all_countries    = WC()->countries->get_countries();
	$eu_countries     = WC()->countries->get_european_union_countries();
	$eu_vat_countries = WC()->countries->get_european_union_countries( 'eu_vat' );

	return apply_filters( 
		'wpo_wcpdf_templates_country_groups', 
		array(
			'ASEAN'      => array(
				'label'     => __( 'ASEAN countries', 'wpo_wcpdf_templates' ),
				'countries' => array( 'BN', 'ID', 'KH', 'LA', 'MM', 'MY', 'PH', 'SG', 'TH', 'VN' )
			),
			'BRICS'      => array(
				'label'     => __( 'BRICS countries', 'wpo_wcpdf_templates' ),
				'countries' => array( 'BR', 'RU', 'IN', 'CN', 'ZA', 'SA', 'EG', 'AE', 'ET', 'ID', 'IR' )
			),
			'EAC'        => array(
				'label'     => __( 'EAC countries', 'wpo_wcpdf_templates' ),
				'countries' => array( 'CD', 'BI', 'KE', 'RW', 'SO', 'SS', 'UG', 'TZ' )
			),
			'EFTA'       => array(
				'label'     => __( 'EFTA countries', 'wpo_wcpdf_templates' ),
				'countries' => array( 'CH', 'IS', 'LI', 'NO' )
			),
			'EU'         => array(
				'label'     => __( 'EU countries', 'wpo_wcpdf_templates' ),
				'countries' => $eu_countries
			),
			'NON_EU'     => array(
				'label'     => __( 'Non-EU countries', 'wpo_wcpdf_templates' ),
				'countries' => array_diff( array_keys( $all_countries ), $eu_countries )
			),
			'NON_EU_VAT' => array(
				'label'     => __( 'Non-EU VAT countries', 'wpo_wcpdf_templates' ),
				'countries' => array_diff( array_keys( $all_countries ), $eu_vat_countries )
			)
		)
	);
}
