<?php
/**
 * Persists product picker and bulk selections across nested settings saves.
 *
 * @package PhoenixWP\PriceLabels\Admin
 */

declare(strict_types=1);

namespace PhoenixWP\PriceLabels\Admin;

defined( 'ABSPATH' ) || exit;

/**
 * Stores generator form selections per admin user (survives PRG redirects).
 */
final class Generator_Form_State {

	public const USER_META_KEY = 'phoenix_wp_price_labels_generator_form_state';

	/**
	 * @return array<string, mixed>
	 */
	public static function defaults(): array {
		return array(
			'picker_product_ids'        => '',
			'picker_product_quantities' => '',
			'picker_repeat_enabled'     => false,
			'product_ids'               => '',
			'bulk_category_ids'         => array(),
			'bulk_filter_on_sale'       => false,
			'bulk_filter_in_stock'      => false,
			'bulk_filter_price_since'   => '',
			'label_repeat'              => 1,
			'bulk_expand_variations'    => true,
		);
	}

	/**
	 * @return array<string, mixed>
	 */
	public static function get_for_current_user(): array {
		$user_id = get_current_user_id();

		if ( $user_id <= 0 ) {
			return self::defaults();
		}

		$stored = get_user_meta( $user_id, self::USER_META_KEY, true );

		if ( ! is_array( $stored ) ) {
			return self::defaults();
		}

		return self::sanitize( $stored );
	}

	/**
	 * @param array<string, mixed> $request Raw admin POST (or stored state array).
	 */
	public static function capture_from_request( array $request ): void {
		$user_id = get_current_user_id();

		if ( $user_id <= 0 || ! current_user_can( 'manage_woocommerce' ) ) {
			return;
		}

		update_user_meta( $user_id, self::USER_META_KEY, self::sanitize( $request ) );
	}

	/**
	 * @param array<string, mixed> $request Raw admin POST (or stored state array).
	 *
	 * @return array<string, mixed>
	 */
	public static function sanitize( array $request ): array {
		$defaults = self::defaults();

		$picker_ids = isset( $request['picker_product_ids'] )
			? self::sanitize_id_csv( (string) $request['picker_product_ids'] )
			: (string) $defaults['picker_product_ids'];

		$picker_quantities = isset( $request['picker_product_quantities'] )
			? self::sanitize_quantity_pairs( (string) $request['picker_product_quantities'] )
			: (string) $defaults['picker_product_quantities'];

		$product_ids = isset( $request['product_ids'] )
			? self::sanitize_id_csv( (string) $request['product_ids'] )
			: (string) $defaults['product_ids'];

		$bulk_category_ids = array();
		if ( isset( $request['bulk_category_ids'] ) && is_array( $request['bulk_category_ids'] ) ) {
			$bulk_category_ids = array_values(
				array_unique(
					array_filter( array_map( 'absint', $request['bulk_category_ids'] ) )
				)
			);
		} elseif ( isset( $request['bulk_category_ids'] ) && is_string( $request['bulk_category_ids'] ) ) {
			$bulk_category_ids = array_values(
				array_unique(
					array_filter( array_map( 'absint', preg_split( '/[\s,;]+/', $request['bulk_category_ids'] ) ?: array() ) )
				)
			);
		}

		$label_repeat = isset( $request['label_repeat'] ) ? absint( (string) $request['label_repeat'] ) : (int) $defaults['label_repeat'];
		$label_repeat = max( 1, min( 99, $label_repeat ) );

		$price_since = isset( $request['bulk_filter_price_since'] )
			? self::sanitize_date( (string) $request['bulk_filter_price_since'] )
			: (string) $defaults['bulk_filter_price_since'];

		return array(
			'picker_product_ids'        => $picker_ids,
			'picker_product_quantities' => $picker_quantities,
			'picker_repeat_enabled'     => ! empty( $request['picker_repeat_enabled'] )
				&& '1' === (string) $request['picker_repeat_enabled'],
			'product_ids'               => $product_ids,
			'bulk_category_ids'         => $bulk_category_ids,
			'bulk_filter_on_sale'       => ! empty( $request['bulk_filter_on_sale'] ),
			'bulk_filter_in_stock'      => ! empty( $request['bulk_filter_in_stock'] ),
			'bulk_filter_price_since'   => $price_since,
			'label_repeat'              => $label_repeat,
			'bulk_expand_variations'    => ! isset( $request['bulk_expand_variations'] )
				|| ! empty( $request['bulk_expand_variations'] ),
		);
	}

	private static function sanitize_id_csv( string $raw ): string {
		$ids = array_filter( array_map( 'absint', preg_split( '/[\s,;]+/', $raw ) ?: array() ) );

		return implode( ',', $ids );
	}

	private static function sanitize_quantity_pairs( string $raw ): string {
		$raw   = trim( $raw );
		$pairs = array();

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

		foreach ( preg_split( '/\s*,\s*/', $raw ) ?: array() as $segment ) {
			$parts = explode( ':', (string) $segment, 2 );

			if ( 2 !== count( $parts ) ) {
				continue;
			}

			$id  = absint( trim( $parts[0] ) );
			$qty = absint( trim( $parts[1] ) );

			if ( $id <= 0 || $qty <= 0 ) {
				continue;
			}

			$pairs[] = $id . ':' . min( 99, max( 1, $qty ) );
		}

		return implode( ',', $pairs );
	}

	private static function sanitize_date( string $date ): string {
		$date = trim( $date );

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

		$parsed = \DateTimeImmutable::createFromFormat( 'Y-m-d', $date );

		if ( false === $parsed ) {
			return '';
		}

		return $parsed->format( 'Y-m-d' );
	}
}
