<?php
/**
 * Size trait — PHP CSS emit. Owns width / height / min-* / max-* per-
 * field longhand for any block declaring `"blocksifySupports": [...,
 * "size"]`. Mirrors JS `buildSizeDecls` byte-for-byte.
 *
 * Per-device cascade with override layers (tablet/mobile) threading
 * cascade source so a cleared field over a meaningful base emits explicit
 * reset (`width: auto;` / `max-width: none;` / etc) — kills cascade
 * leakage. NOT hover-aware (structural per FOUNDATION §6.4).
 *
 * @package Blocksify
 */

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

class Blocksify_Size_Trait {

	/**
	 * Attribute schema fragment. Mirror of `src/shared/traits/size.js`
	 * `attributes` const. See spacing trait header for rationale + sync rule.
	 */
	public static function attributes() {
		return array(
			'size'        => array( 'type' => array( 'object', 'null' ) ),
			'sizeTablet'  => array( 'type' => array( 'object', 'null' ) ),
			'sizeMobile'  => array( 'type' => array( 'object', 'null' ) ),
		);
	}

	/**
	 * Wrapper-rule size decls for one device.
	 *
	 * @param string $part_prefix Optional part name (SPEC-trait-parts §3.3).
	 */
	public static function emit_decls( $attrs, $device, $part_prefix = '' ) {
		return self::build_decls(
			self::resolve_bag( $attrs, $device, $part_prefix ),
			'desktop' === $device ? null : self::cascade_base( $attrs, $device, $part_prefix )
		);
	}

	/**
	 * Resolve the active-device size bag with cascade.
	 */
	protected static function resolve_bag( $attrs, $device, $part_prefix = '' ) {
		$mobile_key  = Blocksify_Attrs::part_key( $part_prefix, 'size', 'mobile' );
		$tablet_key  = Blocksify_Attrs::part_key( $part_prefix, 'size', 'tablet' );
		$desktop_key = Blocksify_Attrs::part_key( $part_prefix, 'size', 'desktop' );
		if ( 'mobile' === $device && isset( $attrs[ $mobile_key ] ) && is_array( $attrs[ $mobile_key ] ) ) {
			return $attrs[ $mobile_key ];
		}
		if ( ( 'mobile' === $device || 'tablet' === $device )
			&& isset( $attrs[ $tablet_key ] ) && is_array( $attrs[ $tablet_key ] ) ) {
			return $attrs[ $tablet_key ];
		}
		return isset( $attrs[ $desktop_key ] ) && is_array( $attrs[ $desktop_key ] )
			? $attrs[ $desktop_key ]
			: null;
	}

	/**
	 * Cascade source bag for non-desktop. Tablet→desktop;
	 * Mobile→tablet (when meaningful) else desktop.
	 */
	protected static function cascade_base( $attrs, $device, $part_prefix = '' ) {
		$tablet_key  = Blocksify_Attrs::part_key( $part_prefix, 'size', 'tablet' );
		$desktop_key = Blocksify_Attrs::part_key( $part_prefix, 'size', 'desktop' );
		if ( 'tablet' === $device ) {
			return isset( $attrs[ $desktop_key ] ) && is_array( $attrs[ $desktop_key ] )
				? $attrs[ $desktop_key ]
				: null;
		}
		if ( isset( $attrs[ $tablet_key ] ) && is_array( $attrs[ $tablet_key ] ) ) {
			return $attrs[ $tablet_key ];
		}
		return isset( $attrs[ $desktop_key ] ) && is_array( $attrs[ $desktop_key ] )
			? $attrs[ $desktop_key ]
			: null;
	}

	/**
	 * Build the size decls (width / height / min-* / max-*). Per-field
	 * longhand. When `$base_bag` provided AND override field is null over
	 * a meaningful base, emit field's reset token to kill cascade.
	 */
	protected static function build_decls( $bag, $base_bag = null ) {
		if ( ! is_array( $bag ) ) {
			return '';
		}
		$fields = array(
			array( 'width', 'width', 'auto' ),
			array( 'height', 'height', 'auto' ),
			array( 'minWidth', 'min-width', '0' ),
			array( 'minHeight', 'min-height', '0' ),
			array( 'maxWidth', 'max-width', 'none' ),
			array( 'maxHeight', 'max-height', 'none' ),
		);
		$decls = '';
		foreach ( $fields as $entry ) {
			list( $key, $prop, $reset ) = $entry;
			$formatted = self::format_field(
				isset( $bag[ $key ] ) ? $bag[ $key ] : null
			);
			if ( null !== $formatted ) {
				$decls .= $prop . ': ' . $formatted . ';';
				continue;
			}
			if ( is_array( $base_bag ) ) {
				$base_formatted = self::format_field(
					isset( $base_bag[ $key ] ) ? $base_bag[ $key ] : null
				);
				if ( null !== $base_formatted ) {
					$decls .= $prop . ': ' . $reset . ';';
				}
			}
		}
		return $decls;
	}

	protected static function format_field( $field ) {
		if ( ! is_array( $field ) ) {
			return null;
		}
		if ( ! isset( $field['value'] ) || ! is_numeric( $field['value'] ) ) {
			return null;
		}
		if ( empty( $field['unit'] ) || ! is_string( $field['unit'] ) ) {
			return null;
		}
		return ( (float) $field['value'] ) . $field['unit'];
	}
}
