<?php
/**
 * Sheet layout definitions (Avery, plain paper).
 *
 * @package PhoenixWP\PriceLabels
 */

declare(strict_types=1);

namespace PhoenixWP\PriceLabels\Pdf;

defined( 'ABSPATH' ) || exit;

/**
 * Label sheet geometry (mm) for PDF rendering.
 */
final class Sheet_Layout {

	public const PRESET_L7159             = 'l7159';
	public const PRESET_L7160             = 'l7160';
	public const PRESET_L7163             = 'l7163';
	public const PRESET_PLAIN_STRIP_39 = 'plain_strip_39';
	public const PRESET_PLAIN_STRIP_30 = 'plain_strip_30';

	public const GROUP_AVERY       = 'avery';
	public const GROUP_PLAIN_PAPER = 'plain_paper';

	/** Label heights up to this (mm) use the two-row title + aligned price layout. */
	public const COMPACT_LABEL_MAX_MM = 40.0;

	/** With scan codes enabled, title rows are capped at one line up to this label height (mm). */
	public const SCAN_CODE_SINGLE_TITLE_MAX_MM = 35.0;

	/** @var array<string, array<string, float|int|string|array<int, float>|array<string, string|int>>> */
	private const PRESETS = array(
		self::PRESET_L7159 => array(
			'name'             => 'Avery L7159 (24-up A4)',
			'page_width'       => 210.0,
			'page_height'      => 297.0,
			'label_width'      => 63.5,
			'label_height'     => 33.9,
			'columns'          => 3,
			'rows'             => 8,
			'margin_top'       => 13.1,
			'margin_left'      => 7.2,
			'horizontal_pitch' => 66.0,
			'vertical_pitch'   => 33.9,
			'tier'             => 'free',
			'group'            => self::GROUP_AVERY,
			'typography'       => array(
				'name_size'        => '7.5pt',
				'name_height'      => '9mm',
				'name_line_height' => '4.2mm',
				'name_lines'       => 2,
				'price_size'       => '10pt',
				'unit_size'        => '6pt',
				'meta_size'        => '5.5pt',
				'var_size'         => '6.5pt',
				'pad'              => '1mm 1.5mm',
			),
		),
		self::PRESET_L7160 => array(
			'name'             => 'Avery L7160 (21-up A4)',
			'page_width'       => 210.0,
			'page_height'      => 297.0,
			'label_width'      => 63.5,
			'label_height'     => 38.1,
			'columns'          => 3,
			'rows'             => 7,
			'margin_top'       => 15.1,
			'margin_left'      => 7.2,
			'horizontal_pitch' => 66.0,
			'vertical_pitch'   => 38.1,
			'tier'             => 'free',
			'group'            => self::GROUP_AVERY,
			'typography'       => array(
				'name_size'        => '7.5pt',
				'name_height'      => '9mm',
				'name_line_height' => '4.2mm',
				'name_lines'       => 2,
				'price_size'       => '10pt',
				'unit_size'        => '6pt',
				'meta_size'        => '5.5pt',
				'var_size'         => '6.5pt',
				'pad'              => '1mm 1.5mm',
			),
		),
		self::PRESET_L7163 => array(
			'name'             => 'Avery L7163 (14-up A4)',
			'page_width'       => 210.0,
			'page_height'      => 297.0,
			'label_width'      => 99.1,
			'label_height'     => 38.1,
			'columns'          => 2,
			'rows'             => 7,
			'margin_top'       => 15.1,
			'margin_left'      => 4.6,
			'horizontal_pitch' => 103.0,
			'vertical_pitch'   => 38.1,
			'tier'             => 'free',
			'group'            => self::GROUP_AVERY,
			'typography'       => array(
				'name_size'        => '7.5pt',
				'name_height'      => '9mm',
				'name_line_height' => '4.2mm',
				'name_lines'       => 2,
				'price_size'       => '10pt',
				'unit_size'        => '6pt',
				'meta_size'        => '5.5pt',
				'var_size'         => '6.5pt',
				'pad'              => '1mm 1.5mm',
			),
		),
		self::PRESET_PLAIN_STRIP_39 => array(
			'name'             => 'Plain paper — 39 mm strip (TE 39)',
			'page_width'       => 210.0,
			'page_height'      => 297.0,
			'label_width'      => 190.0,
			'label_height'     => 39.0,
			'columns'          => 1,
			'rows'             => 7,
			'margin_top'       => 10.0,
			'margin_left'      => 10.0,
			'horizontal_pitch' => 190.0,
			'vertical_pitch'   => 39.0,
			'tier'             => 'free',
			'group'            => self::GROUP_PLAIN_PAPER,
			'typography'       => array(
				'name_size'        => '7.5pt',
				'name_height'      => '9mm',
				'name_line_height' => '4.2mm',
				'name_lines'       => 2,
				'price_size'       => '10pt',
				'unit_size'        => '6pt',
				'meta_size'        => '5.5pt',
				'var_size'         => '6.5pt',
				'pad'              => '1mm 2mm',
			),
		),
		self::PRESET_PLAIN_STRIP_30 => array(
			'name'             => 'Plain paper — 30 mm strip (TE / Universal 30)',
			'page_width'       => 210.0,
			'page_height'      => 297.0,
			'label_width'      => 190.0,
			'label_height'     => 30.0,
			'columns'          => 1,
			'rows'             => 9,
			'margin_top'       => 10.0,
			'margin_left'      => 10.0,
			'horizontal_pitch' => 190.0,
			'vertical_pitch'   => 30.0,
			'tier'             => 'free',
			'group'            => self::GROUP_PLAIN_PAPER,
			'typography'       => array(
				'name_size'        => '7.5pt',
				'name_height'      => '9mm',
				'name_line_height' => '4.2mm',
				'name_lines'       => 2,
				'price_size'  => '10pt',
				'unit_size'   => '6pt',
				'meta_size'   => '5.5pt',
				'var_size'    => '6.5pt',
				'pad'         => '1mm 2mm',
			),
		),
	);

	private string $preset;

	public function __construct( string $preset = self::PRESET_L7159 ) {
		$allowed      = self::get_allowed_preset_keys();
		$this->preset = in_array( $preset, $allowed, true ) ? $preset : self::PRESET_L7159;
	}

	/**
	 * @return string[]
	 */
	public static function get_free_presets(): array {
		return self::filter_presets_by_tier( 'free' );
	}

	/**
	 * @return string[]
	 */
	public static function get_avery_presets(): array {
		return self::filter_presets_by_group( self::GROUP_AVERY );
	}

	/**
	 * @return string[]
	 */
	public static function get_plain_paper_presets(): array {
		return self::filter_presets_by_group( self::GROUP_PLAIN_PAPER );
	}

	/**
	 * @return string[]
	 */
	public static function get_badgemaker_presets(): array {
		return array();
	}

	/**
	 * Presets available in this distribution.
	 *
	 * @return string[]
	 */
	public static function get_allowed_preset_keys(): array {
		$keys = self::get_free_presets();

		/**
		 * Filters selectable sheet preset keys.
		 *
		 * @param string[] $keys Preset slugs.
		 */
		return array_values( array_unique( (array) apply_filters( 'phoenix_wp_price_labels_sheet_presets', $keys ) ) );
	}

	/**
	 * @return string[]
	 */
	private static function filter_presets_by_tier( string $tier ): array {
		$keys = array();

		foreach ( self::PRESETS as $key => $config ) {
			if ( ( $config['tier'] ?? '' ) === $tier ) {
				$keys[] = $key;
			}
		}

		return $keys;
	}

	/**
	 * @return string[]
	 */
	private static function filter_presets_by_group( string $group ): array {
		$keys = array();

		foreach ( self::PRESETS as $key => $config ) {
			if ( ( $config['group'] ?? '' ) === $group && 'free' === ( $config['tier'] ?? '' ) ) {
				$keys[] = $key;
			}
		}

		return $keys;
	}

	public function get_preset_key(): string {
		return $this->preset;
	}

	public function get_name(): string {
		return (string) self::PRESETS[ $this->preset ]['name'];
	}

	public function labels_per_sheet(): int {
		return (int) self::PRESETS[ $this->preset ]['columns'] * (int) self::PRESETS[ $this->preset ]['rows'];
	}

	public function is_compact(): bool {
		return (float) $this->get_dimensions()['label_height'] <= self::COMPACT_LABEL_MAX_MM;
	}

	/**
	 * @return array<string, float|int|string|array<int, float>|array<string, string|int>>
	 */
	public function get_dimensions(): array {
		/** @var array<string, float|int|string|array<int, float>|array<string, string|int>> $dims */
		$dims = self::PRESETS[ $this->preset ];

		/**
		 * Filters sheet geometry before PDF rendering.
		 *
		 * @param array<string, mixed> $dims   Layout dimensions.
		 * @param string               $preset Preset key.
		 */
		return (array) apply_filters( 'phoenix_wp_price_labels_sheet_dimensions', $dims, $this->preset );
	}
}
