<?php
/**
 * Materials Library — a digital product catalog for tile, wallpaper, and
 * (in future) any other real-world surface material a factory sells.
 *
 * Deliberately a real WP admin form, not a JSON textarea: manufacturers
 * fill in the specs already printed on their own product data sheet
 * (name, SKU, image, physical dimensions, price) and the renderer
 * (assets/js/app.js) works out repeat/scale automatically. No Three.js,
 * UV, or JSON knowledge required.
 */

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

define( 'TILVORA_MATERIAL_CPT', 'tilvora_material' );

/* ── Register CPT ─────────────────────────────────────────────────── */

add_action( 'init', 'tilvora_register_material_cpt' );

function tilvora_register_material_cpt() {
	$labels = [
		'name'               => __( 'Materials',                      'tilvora-3d-flooring-visualizer' ),
		'singular_name'      => __( 'Material',                       'tilvora-3d-flooring-visualizer' ),
		'add_new'            => __( 'Add New',                        'tilvora-3d-flooring-visualizer' ),
		'add_new_item'       => __( 'Add New Material',               'tilvora-3d-flooring-visualizer' ),
		'edit_item'          => __( 'Edit Material',                  'tilvora-3d-flooring-visualizer' ),
		'new_item'           => __( 'New Material',                   'tilvora-3d-flooring-visualizer' ),
		'view_item'          => __( 'View Material',                  'tilvora-3d-flooring-visualizer' ),
		'search_items'       => __( 'Search Materials',               'tilvora-3d-flooring-visualizer' ),
		'not_found'          => __( 'No materials found.',            'tilvora-3d-flooring-visualizer' ),
		'not_found_in_trash' => __( 'No materials found in trash.',   'tilvora-3d-flooring-visualizer' ),
		'menu_name'          => __( 'Materials Library',              'tilvora-3d-flooring-visualizer' ),
	];

	register_post_type( TILVORA_MATERIAL_CPT, [
		'labels'             => $labels,
		'public'             => false,
		'publicly_queryable' => false,
		'show_ui'            => true,
		'show_in_menu'       => 'edit.php?post_type=' . TILVORA_CPT,
		'show_in_nav_menus'  => false,
		'show_in_admin_bar'  => false,
		'query_var'          => false,
		'rewrite'            => false,
		'capability_type'    => 'post',
		'has_archive'        => false,
		'hierarchical'       => false,
		'menu_icon'          => 'dashicons-images-alt2',
		'supports'           => [ 'title' ],
	] );
}

/* ── Meta keys ────────────────────────────────────────────────────── */

function tilvora_material_meta_fields() {
	return [
		'sku'              => [ 'label' => __( 'SKU', 'tilvora-3d-flooring-visualizer' ), 'type' => 'text' ],
		'category'         => [ 'label' => __( 'Category', 'tilvora-3d-flooring-visualizer' ), 'type' => 'text', 'placeholder' => __( 'e.g. Marble, Ceramic Tile, Wallpaper', 'tilvora-3d-flooring-visualizer' ) ],
		'finish'           => [ 'label' => __( 'Finish', 'tilvora-3d-flooring-visualizer' ), 'type' => 'text', 'placeholder' => __( 'e.g. Polished, Matte', 'tilvora-3d-flooring-visualizer' ) ],
		'price'            => [ 'label' => __( 'Price', 'tilvora-3d-flooring-visualizer' ), 'type' => 'number', 'step' => '0.01' ],
		'unit'             => [ 'label' => __( 'Price Unit', 'tilvora-3d-flooring-visualizer' ), 'type' => 'text', 'placeholder' => 'm²' ],
		'width_mm'         => [ 'label' => __( 'Width (cm)', 'tilvora-3d-flooring-visualizer' ), 'type' => 'number', 'unit_scale' => 10, 'help' => __( 'Tile: the tile\'s width. Wallpaper: the roll width.', 'tilvora-3d-flooring-visualizer' ) ],
		'height_mm'        => [ 'label' => __( 'Height (cm)', 'tilvora-3d-flooring-visualizer' ), 'type' => 'number', 'unit_scale' => 10, 'help' => __( 'Tile: the tile\'s height. Wallpaper: the pattern repeat length.', 'tilvora-3d-flooring-visualizer' ) ],
		'thickness_mm'     => [ 'label' => __( 'Thickness (mm)', 'tilvora-3d-flooring-visualizer' ), 'type' => 'number' ],
		'roll_length_mm'   => [ 'label' => __( 'Roll Length (cm)', 'tilvora-3d-flooring-visualizer' ), 'type' => 'number', 'unit_scale' => 10, 'help' => __( 'Wallpaper only. Not used for rendering — only for estimating rolls needed.', 'tilvora-3d-flooring-visualizer' ) ],
		'roll_coverage_m2' => [ 'label' => __( 'Roll Coverage (m²)', 'tilvora-3d-flooring-visualizer' ), 'type' => 'number', 'step' => '0.01', 'help' => __( 'Wallpaper only. Not used for rendering — only for estimating rolls needed.', 'tilvora-3d-flooring-visualizer' ) ],
		'target'           => [ 'label' => __( 'Applies To (mesh target)', 'tilvora-3d-flooring-visualizer' ), 'type' => 'text', 'default' => 'floor', 'help' => __( 'Must match a meshTargets key in the product\'s config, e.g. "floor" or "wall". Only materials matching a material-grid control\'s own target appear in that tab.', 'tilvora-3d-flooring-visualizer' ) ],
		'mapping_mode'     => [ 'label' => __( 'Mapping Mode', 'tilvora-3d-flooring-visualizer' ), 'type' => 'select', 'options' => [ 'repeat' => __( 'Repeat (tile / wallpaper)', 'tilvora-3d-flooring-visualizer' ), 'fit' => __( 'Fit (reserved for future use)', 'tilvora-3d-flooring-visualizer' ) ], 'default' => 'repeat' ],
	];
}

function tilvora_material_meta_key( $field ) {
	return '_tilvora_mat_' . $field;
}

/* ── Metabox: product image ──────────────────────────────────────── */

add_action( 'add_meta_boxes_' . TILVORA_MATERIAL_CPT, 'tilvora_register_material_metaboxes' );

function tilvora_register_material_metaboxes() {
	add_meta_box(
		'tilvora_material_image',
		__( 'Product Image', 'tilvora-3d-flooring-visualizer' ),
		'tilvora_render_material_image_metabox',
		TILVORA_MATERIAL_CPT,
		'side',
		'default'
	);
	add_meta_box(
		'tilvora_material_specs',
		__( 'Product Specification', 'tilvora-3d-flooring-visualizer' ),
		'tilvora_render_material_specs_metabox',
		TILVORA_MATERIAL_CPT,
		'normal',
		'high'
	);
}

function tilvora_render_material_image_metabox( $post ) {
	wp_nonce_field( 'tilvora_save_material', 'tilvora_material_nonce' );
	$image_id = absint( get_post_meta( $post->ID, tilvora_material_meta_key( 'image_id' ), true ) );
	$image_url = $image_id ? wp_get_attachment_image_url( $image_id, 'medium' ) : '';
	?>
	<div id="tilvora-material-image-wrap">
		<div id="tilvora-material-image-preview" style="margin-bottom:10px;<?php echo $image_url ? '' : 'display:none;'; ?>">
			<img src="<?php echo esc_url( $image_url ?: '' ); ?>" style="max-width:100%;height:auto;border:1px solid #dcdcde;border-radius:4px;" />
		</div>
		<p class="description"><?php esc_html_e( 'One product photo is all that\'s needed — the visualizer generates thumbnail and full-resolution sizes from it automatically.', 'tilvora-3d-flooring-visualizer' ); ?></p>
		<input type="hidden" id="tilvora-material-image-id" name="tilvora_material_image_id" value="<?php echo esc_attr( $image_id ); ?>" />
		<p>
			<button type="button" class="button" id="tilvora-material-image-select"><?php echo $image_id ? esc_html__( 'Change Image', 'tilvora-3d-flooring-visualizer' ) : esc_html__( 'Select Image', 'tilvora-3d-flooring-visualizer' ); ?></button>
			<button type="button" class="button" id="tilvora-material-image-remove" style="<?php echo $image_id ? '' : 'display:none;'; ?>"><?php esc_html_e( 'Remove', 'tilvora-3d-flooring-visualizer' ); ?></button>
		</p>
	</div>
	<?php
}

function tilvora_render_material_specs_metabox( $post ) {
	$fields = tilvora_material_meta_fields();
	echo '<table class="form-table">';
	foreach ( $fields as $key => $field ) {
		$meta_key = tilvora_material_meta_key( $key );
		$value    = get_post_meta( $post->ID, $meta_key, true );
		if ( '' === $value && isset( $field['default'] ) ) {
			$value = $field['default'];
		}
		if ( '' !== $value && ! empty( $field['unit_scale'] ) ) {
			$value = $value / $field['unit_scale'];
		}
		$name = 'tilvora_material_' . $key;
		echo '<tr><th><label for="' . esc_attr( $name ) . '">' . esc_html( $field['label'] ) . '</label></th><td>';

		if ( 'select' === $field['type'] ) {
			echo '<select id="' . esc_attr( $name ) . '" name="' . esc_attr( $name ) . '">';
			foreach ( $field['options'] as $opt_val => $opt_label ) {
				echo '<option value="' . esc_attr( $opt_val ) . '" ' . selected( $value, $opt_val, false ) . '>' . esc_html( $opt_label ) . '</option>';
			}
			echo '</select>';
		} else {
			$step = isset( $field['step'] ) ? ' step="' . esc_attr( $field['step'] ) . '"' : ( 'number' === $field['type'] ? ' step="any"' : '' );
			echo '<input type="' . esc_attr( $field['type'] ) . '" id="' . esc_attr( $name ) . '" name="' . esc_attr( $name ) . '" value="' . esc_attr( $value ) . '"'
				. ( isset( $field['placeholder'] ) ? ' placeholder="' . esc_attr( $field['placeholder'] ) . '"' : '' )
				. $step // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- $step is built above entirely from esc_attr( $field['step'] ) or a hardcoded literal; sniff can't trace escaping through the intermediate variable.
				. ' class="regular-text" />';
		}

		if ( ! empty( $field['help'] ) ) {
			echo '<p class="description">' . esc_html( $field['help'] ) . '</p>';
		}
		echo '</td></tr>';
	}
	echo '</table>';
}

/* ── Media picker script ──────────────────────────────────────────── */

add_action( 'admin_enqueue_scripts', 'tilvora_enqueue_material_admin_assets' );

function tilvora_enqueue_material_admin_assets( $hook ) {
	if ( ! in_array( $hook, [ 'post.php', 'post-new.php' ], true ) ) {
		return;
	}
	$screen = get_current_screen();
	if ( ! $screen || TILVORA_MATERIAL_CPT !== $screen->post_type ) {
		return;
	}
	wp_enqueue_media();

	$js = "(function () {"
		. "var frame;"
		. "var selectBtn = document.getElementById('tilvora-material-image-select');"
		. "var removeBtn = document.getElementById('tilvora-material-image-remove');"
		. "var idInput   = document.getElementById('tilvora-material-image-id');"
		. "var preview   = document.getElementById('tilvora-material-image-preview');"
		. "if (!selectBtn) return;"
		. "selectBtn.addEventListener('click', function (e) {"
		. "  e.preventDefault();"
		. "  if (!window.wp || !wp.media) return;"
		. "  if (!frame) {"
		. "    frame = wp.media({ title: 'Select Product Image', button: { text: 'Use this image' }, multiple: false, library: { type: 'image' } });"
		. "    frame.on('select', function () {"
		. "      var att = frame.state().get('selection').first().toJSON();"
		. "      idInput.value = att.id;"
		. "      var url = (att.sizes && att.sizes.medium) ? att.sizes.medium.url : att.url;"
		. "      preview.querySelector('img').src = url;"
		. "      preview.style.display = '';"
		. "      removeBtn.style.display = '';"
		. "      selectBtn.textContent = 'Change Image';"
		. "    });"
		. "  }"
		. "  frame.open();"
		. "});"
		. "removeBtn.addEventListener('click', function (e) {"
		. "  e.preventDefault();"
		. "  idInput.value = '';"
		. "  preview.style.display = 'none';"
		. "  removeBtn.style.display = 'none';"
		. "  selectBtn.textContent = 'Select Image';"
		. "});"
		. "})();";

	// "Duplicate" button next to "Add New Material" on the edit screen itself
	// (not just the list-table row action) — same clone-post-as-draft handler,
	// just a second, more visible entry point to it while already editing a
	// material a factory admin wants to base a new one on.
	if ( 'post.php' === $hook ) {
		$post_id = isset( $_GET['post'] ) ? absint( $_GET['post'] ) : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only, only used to build a nonce'd link.
		if ( $post_id && current_user_can( 'edit_post', $post_id ) ) {
			// wp_nonce_url() HTML-escapes its return value (& -> &amp;) for
			// direct use in href="..." markup; here it's going into a JS
			// string instead (dup.href = "..."), which never HTML-decodes,
			// so it must be un-escaped first or the nonce/post params break.
			$dup_url = html_entity_decode(
				wp_nonce_url(
					add_query_arg( [ 'action' => 'tilvora_duplicate_material', 'post' => $post_id ], admin_url( 'admin.php' ) ),
					'tilvora_duplicate_material_' . $post_id
				),
				ENT_QUOTES
			);
			$js .= "(function () {"
				. "var addNew = document.querySelector('.page-title-action');"
				. "if (!addNew || document.getElementById('tilvora-duplicate-btn')) return;"
				. "var dup = document.createElement('a');"
				. "dup.id = 'tilvora-duplicate-btn';"
				. "dup.className = 'page-title-action';"
				. "dup.href = " . wp_json_encode( $dup_url ) . ';'
				. "dup.textContent = " . wp_json_encode( __( 'Duplicate', 'tilvora-3d-flooring-visualizer' ) ) . ';'
				. "addNew.insertAdjacentElement('afterend', dup);"
				. "})();";
		}
	}

	wp_register_script( 'tilvora-material-image', false, [], TILVORA_VERSION, true );
	wp_enqueue_script( 'tilvora-material-image' );
	wp_add_inline_script( 'tilvora-material-image', $js );
}

/* ── Save ─────────────────────────────────────────────────────────── */

add_action( 'save_post_' . TILVORA_MATERIAL_CPT, 'tilvora_save_material_meta' );

function tilvora_save_material_meta( $post_id ) {
	$nonce = isset( $_POST['tilvora_material_nonce'] ) ? sanitize_text_field( wp_unslash( $_POST['tilvora_material_nonce'] ) ) : '';
	if ( ! $nonce || ! wp_verify_nonce( $nonce, 'tilvora_save_material' ) ) {
		return;
	}
	if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
		return;
	}
	if ( ! current_user_can( 'edit_post', $post_id ) ) {
		return;
	}

	if ( isset( $_POST['tilvora_material_image_id'] ) ) {
		update_post_meta( $post_id, tilvora_material_meta_key( 'image_id' ), absint( $_POST['tilvora_material_image_id'] ) );
	}

	$fields = tilvora_material_meta_fields();
	foreach ( $fields as $key => $field ) {
		$name = 'tilvora_material_' . $key;
		if ( ! isset( $_POST[ $name ] ) ) {
			continue;
		}
		// phpcs:ignore WordPress.Security.ValidatedSanitizedInput.InputNotSanitized -- sanitized a few lines below per $field['type'] (floatval/allowlist/sanitize_text_field).
		$raw = wp_unslash( $_POST[ $name ] );
		if ( 'number' === $field['type'] ) {
			$clean = ( '' === trim( (string) $raw ) ) ? '' : floatval( $raw );
			if ( '' !== $clean && ! empty( $field['unit_scale'] ) ) {
				$clean = $clean * $field['unit_scale'];
			}
		} elseif ( 'select' === $field['type'] ) {
			$allowed = array_keys( $field['options'] );
			$clean   = in_array( $raw, $allowed, true ) ? $raw : ( $field['default'] ?? $allowed[0] );
		} else {
			$clean = sanitize_text_field( $raw );
		}
		update_post_meta( $post_id, tilvora_material_meta_key( $key ), $clean );
	}
}

/* ── List table: show the fields a factory admin actually scans for ── */

add_filter( 'manage_' . TILVORA_MATERIAL_CPT . '_posts_columns', 'tilvora_material_columns' );
function tilvora_material_columns( $columns ) {
	$new = [];
	foreach ( $columns as $key => $label ) {
		if ( 'title' === $key ) {
			$new['tilvora_thumb'] = __( 'Image', 'tilvora-3d-flooring-visualizer' );
		}
		$new[ $key ] = $label;
	}
	$new['tilvora_category'] = __( 'Category', 'tilvora-3d-flooring-visualizer' );
	$new['tilvora_target']   = __( 'Target', 'tilvora-3d-flooring-visualizer' );
	$new['tilvora_price']    = __( 'Price', 'tilvora-3d-flooring-visualizer' );
	return $new;
}

add_action( 'manage_' . TILVORA_MATERIAL_CPT . '_posts_custom_column', 'tilvora_material_column_content', 10, 2 );
function tilvora_material_column_content( $column, $post_id ) {
	switch ( $column ) {
		case 'tilvora_thumb':
			$image_id = absint( get_post_meta( $post_id, tilvora_material_meta_key( 'image_id' ), true ) );
			$url      = $image_id ? wp_get_attachment_image_url( $image_id, 'thumbnail' ) : '';
			if ( $url ) {
				echo '<img src="' . esc_url( $url ) . '" style="width:40px;height:40px;object-fit:cover;border-radius:3px;" />';
			}
			break;
		case 'tilvora_category':
			echo esc_html( get_post_meta( $post_id, tilvora_material_meta_key( 'category' ), true ) );
			break;
		case 'tilvora_target':
			echo esc_html( get_post_meta( $post_id, tilvora_material_meta_key( 'target' ), true ) ?: 'floor' );
			break;
		case 'tilvora_price':
			$price = get_post_meta( $post_id, tilvora_material_meta_key( 'price' ), true );
			$unit  = get_post_meta( $post_id, tilvora_material_meta_key( 'unit' ), true );
			if ( '' !== $price ) {
				echo esc_html( $price . ( $unit ? '/' . $unit : '' ) );
			}
			break;
	}
}

/* ── Duplicate — lets a factory admin clone an existing material and
   just change the few fields that differ (a new colorway, a new size)
   instead of re-entering an entire product from scratch. ─────────── */

add_filter( 'post_row_actions', 'tilvora_material_row_actions', 10, 2 );

function tilvora_material_row_actions( $actions, $post ) {
	if ( TILVORA_MATERIAL_CPT !== $post->post_type || ! current_user_can( 'edit_post', $post->ID ) ) {
		return $actions;
	}
	$url = wp_nonce_url(
		add_query_arg(
			[ 'action' => 'tilvora_duplicate_material', 'post' => $post->ID ],
			admin_url( 'admin.php' )
		),
		'tilvora_duplicate_material_' . $post->ID
	);
	$actions['tilvora_duplicate'] = '<a href="' . esc_url( $url ) . '">' . esc_html__( 'Duplicate', 'tilvora-3d-flooring-visualizer' ) . '</a>';
	return $actions;
}

add_action( 'admin_action_tilvora_duplicate_material', 'tilvora_duplicate_material_handler' );

function tilvora_duplicate_material_handler() {
	$post_id = isset( $_GET['post'] ) ? absint( $_GET['post'] ) : 0;
	check_admin_referer( 'tilvora_duplicate_material_' . $post_id );

	if ( ! $post_id || ! current_user_can( 'edit_post', $post_id ) ) {
		wp_die( esc_html__( 'You are not allowed to duplicate this material.', 'tilvora-3d-flooring-visualizer' ) );
	}

	$original = get_post( $post_id );
	if ( ! $original || TILVORA_MATERIAL_CPT !== $original->post_type ) {
		wp_die( esc_html__( 'Material not found.', 'tilvora-3d-flooring-visualizer' ) );
	}

	$new_id = wp_insert_post(
		[
			'post_type'   => TILVORA_MATERIAL_CPT,
			'post_status' => 'draft',
			/* translators: %s: original material name */
			'post_title'  => sprintf( __( '%s (Copy)', 'tilvora-3d-flooring-visualizer' ), $original->post_title ),
		],
		true
	);
	if ( is_wp_error( $new_id ) ) {
		wp_die( esc_html( $new_id->get_error_message() ) );
	}

	foreach ( array_keys( tilvora_material_meta_fields() ) as $key ) {
		$value = get_post_meta( $post_id, tilvora_material_meta_key( $key ), true );
		if ( '' !== $value ) {
			update_post_meta( $new_id, tilvora_material_meta_key( $key ), $value );
		}
	}
	$image_id = absint( get_post_meta( $post_id, tilvora_material_meta_key( 'image_id' ), true ) );
	if ( $image_id ) {
		update_post_meta( $new_id, tilvora_material_meta_key( 'image_id' ), $image_id );
	}

	wp_safe_redirect( admin_url( 'post.php?action=edit&post=' . $new_id ) );
	exit;
}

/* ── Resolve one material post into the JSON shape app.js expects ─── */

function tilvora_get_material_array( $post_id ) {
	$post_id = absint( $post_id );
	$image_id = absint( get_post_meta( $post_id, tilvora_material_meta_key( 'image_id' ), true ) );

	$get = function ( $key ) use ( $post_id ) {
		return get_post_meta( $post_id, tilvora_material_meta_key( $key ), true );
	};

	$width_mm     = $get( 'width_mm' );
	$height_mm    = $get( 'height_mm' );
	$thickness_mm = $get( 'thickness_mm' );
	$roll_length  = $get( 'roll_length_mm' );
	$roll_coverage = $get( 'roll_coverage_m2' );
	$price        = $get( 'price' );

	$material = [
		'id'           => (string) $post_id,
		'name'         => get_the_title( $post_id ),
		'sku'          => $get( 'sku' ),
		'category'     => $get( 'category' ),
		'image'        => $image_id ? wp_get_attachment_image_url( $image_id, 'full' ) : '',
		'thumbnail'    => $image_id ? wp_get_attachment_image_url( $image_id, 'medium' ) : '',
		'dimensions'   => [
			'width_mm'  => '' === $width_mm ? null : (float) $width_mm,
			'height_mm' => '' === $height_mm ? null : (float) $height_mm,
		],
		'finish'       => $get( 'finish' ),
		'price'        => '' === $price ? null : (float) $price,
		'unit'         => $get( 'unit' ) ?: 'm²',
		'target'       => $get( 'target' ) ?: 'floor',
		'mappingMode'  => $get( 'mapping_mode' ) ?: 'repeat',
	];

	if ( '' !== $thickness_mm ) {
		$material['dimensions']['thickness_mm'] = (float) $thickness_mm;
	}
	if ( '' !== $roll_length && '' !== $roll_coverage ) {
		$material['roll'] = [
			'length_mm'   => (float) $roll_length,
			'coverage_m2' => (float) $roll_coverage,
		];
	}

	return $material;
}
