<?php
/**
 * Toggleable label field defaults and per-run resolution.
 *
 * @package PhoenixWP\PriceLabels
 */

declare(strict_types=1);

namespace PhoenixWP\PriceLabels\Labels;

defined( 'ABSPATH' ) || exit;

/**
 * Controls which optional fields appear on standard price labels.
 */
final class Label_Field_Settings {

	public const OPTION_KEY = 'phoenix_wp_price_labels_field_settings';

	/** Always-on fields shown as locked checkboxes in admin (not stored). */
	public const REQUIRED_FIELDS = array(
		'name',
		'price',
	);

	/** Optional fields persisted in shop settings (free distribution). */
	public const TOGGLEABLE_FIELDS = array(
		'brand',
		'variation',
		'unit_price',
		'stock',
		'sku',
		'ean',
	);

	/** Fields that only affect the checkout overview PDF. */
	public const OVERVIEW_ONLY_FIELDS = array(
		'stock',
	);

	/**
	 * @return array<string, bool>
	 */
	/**
	 * Optional fields available for the current distribution / license.
	 *
	 * @return string[]
	 */
	public static function get_toggleable_fields(): array {
		$fields = self::TOGGLEABLE_FIELDS;

		/**
		 * Filters toggleable label fields (e.g. Pro adds `barcode`).
		 *
		 * @param string[] $fields Field slugs.
		 */
		return array_values( array_unique( (array) apply_filters( 'phoenix_wp_price_labels_toggleable_fields', $fields ) ) );
	}

	public static function get_defaults(): array {
		$defaults = self::default_enabled_map();
		$stored   = get_option( self::OPTION_KEY, array() );

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

		foreach ( self::get_toggleable_fields() as $field ) {
			if ( array_key_exists( $field, $stored ) ) {
				$defaults[ $field ] = self::to_bool( $stored[ $field ] );
			}
		}

		/**
		 * Filters shop-default visibility for optional label fields.
		 *
		 * @param array<string, bool> $defaults Field => enabled.
		 */
		$defaults = (array) apply_filters( 'phoenix_wp_price_labels_field_defaults', $defaults );

		return self::apply_required_fields( self::enforce_mutual_exclusive_fields( $defaults ) );
	}

	/**
	 * Resolves field visibility for one PDF run and persists optional toggles.
	 *
	 * @param array<string, mixed>|null $input Raw POST `label_fields` array.
	 *
	 * @return array<string, bool>
	 */
	public static function resolve_for_run( ?array $input = null ): array {
		$resolved = self::default_enabled_map();

		if ( is_array( $input ) ) {
			foreach ( self::get_toggleable_fields() as $field ) {
				$resolved[ $field ] = isset( $input[ $field ] ) && self::to_bool( $input[ $field ] );
			}

			self::save( $input );
		} else {
			$resolved = self::get_defaults();
			foreach ( self::REQUIRED_FIELDS as $field ) {
				unset( $resolved[ $field ] );
			}
		}

		/**
		 * Filters label field visibility for a PDF run.
		 *
		 * @param array<string, bool> $resolved Field => enabled.
		 */
		$resolved = (array) apply_filters( 'phoenix_wp_price_labels_visible_fields', $resolved );

		return self::apply_required_fields( self::enforce_mutual_exclusive_fields( $resolved ) );
	}

	/**
	 * @param array<string, mixed> $input Raw settings from admin.
	 *
	 * @return array<string, bool>
	 */
	public static function sanitize( array $input ): array {
		$clean = self::default_enabled_map();

		foreach ( self::get_toggleable_fields() as $field ) {
			$clean[ $field ] = isset( $input[ $field ] ) && self::to_bool( $input[ $field ] );
		}

		return self::enforce_mutual_exclusive_fields( $clean );
	}

	/**
	 * @param array<string, mixed> $input Raw admin input.
	 */
	public static function save( array $input ): void {
		update_option( self::OPTION_KEY, self::sanitize( $input ), false );
	}

	/**
	 * Human-readable labels for admin UI.
	 *
	 * @return array<string, string>
	 */
	public static function get_field_labels(): array {
		return array(
			'name'       => __( 'Product title', 'phoenix-price-labels-for-woocommerce' ),
			'brand'      => __( 'Brand', 'phoenix-price-labels-for-woocommerce' ),
			'price'      => __( 'Price', 'phoenix-price-labels-for-woocommerce' ),
			'variation'  => __( 'Variation', 'phoenix-price-labels-for-woocommerce' ),
			'unit_price' => __( 'Unit price', 'phoenix-price-labels-for-woocommerce' ),
			'stock'      => __( 'Stock', 'phoenix-price-labels-for-woocommerce' ),
			'sku'        => __( 'SKU', 'phoenix-price-labels-for-woocommerce' ),
			'ean'        => __( 'EAN / GTIN (text)', 'phoenix-price-labels-for-woocommerce' ),
			'barcode'    => __( 'Scan code graphic (EAN-13, Code 128, or QR)', 'phoenix-price-labels-for-woocommerce' ),
		);
	}

	/**
	 * @param array<string, bool> $fields Field map.
	 *
	 * @return array<string, bool>
	 */
	private static function apply_required_fields( array $fields ): array {
		foreach ( self::REQUIRED_FIELDS as $field ) {
			$fields[ $field ] = true;
		}

		return $fields;
	}

	/**
	 * @return array<string, bool>
	 */
	private static function default_enabled_map(): array {
		return array(
			'brand'      => false,
			'variation'  => true,
			'unit_price' => true,
			'stock'      => false,
			'sku'        => true,
			'ean'        => true,
			'barcode'    => false,
		);
	}

	/**
	 * @param mixed $value Raw checkbox value.
	 */
	/**
	 * Scan-code graphic and GTIN text encode the same data — only one may be active.
	 *
	 * @param array<string, bool> $fields Field map.
	 *
	 * @return array<string, bool>
	 */
	private static function enforce_mutual_exclusive_fields( array $fields ): array {
		if ( ! in_array( 'barcode', self::get_toggleable_fields(), true ) ) {
			return $fields;
		}

		if ( ! empty( $fields['barcode'] ) ) {
			$fields['ean'] = false;
		} elseif ( ! empty( $fields['ean'] ) ) {
			$fields['barcode'] = false;
		}

		return $fields;
	}

	/**
	 * @param mixed $value Raw checkbox value.
	 */
	private static function to_bool( mixed $value ): bool {
		if ( is_bool( $value ) ) {
			return $value;
		}

		return in_array( (string) $value, array( '1', 'yes', 'on', 'true' ), true );
	}
}
