<?php
/**
 * Gemeinsame WooCommerce-Helfer für Produkt- und Varianten-Abilities.
 *
 * Alle Lese- und Schreibpfade verwenden ausschließlich die öffentlichen
 * WooCommerce-Objekte und Data Stores. Rohe Postmeta- oder SQL-Zugriffe sind
 * hier bewusst ausgeschlossen, damit Lookup-Tabellen und Objekt-Caches
 * konsistent bleiben.
 *
 * @package WPAgentCompanion
 */

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

/**
 * @return true|WP_Error
 */
function wpagent_require_woocommerce() {
	if ( ! function_exists( 'wc_get_product' ) || ! class_exists( 'WC_Product' ) ) {
		return new WP_Error( 'wpagent_wc_missing', __( 'WooCommerce ist nicht aktiv.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	return true;
}

/**
 * @return WC_Product|WP_Error
 */
function wpagent_get_editable_product( int $product_id ) {
	$available = wpagent_require_woocommerce();
	if ( is_wp_error( $available ) ) {
		return $available;
	}
	$product = wc_get_product( $product_id );
	if ( ! $product || $product->is_type( 'variation' ) ) {
		return new WP_Error( 'wpagent_no_product', __( 'Produkt nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	}
	if ( ! current_user_can( 'edit_post', $product_id ) ) {
		return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	return $product;
}

/**
 * @return array<string, mixed>
 */
function wpagent_wc_product_payload( WC_Product $product ): array {
	$attributes = array();
	foreach ( $product->get_attributes() as $attribute ) {
		if ( ! $attribute instanceof WC_Product_Attribute ) {
			continue;
		}
		$options = $attribute->is_taxonomy()
			? wc_get_product_terms( $product->get_id(), $attribute->get_name(), array( 'fields' => 'names' ) )
			: $attribute->get_options();
		$attributes[] = array(
			'id'        => (int) $attribute->get_id(),
			'name'      => $attribute->get_name(),
			'taxonomy'  => $attribute->is_taxonomy(),
			'options'   => array_values( is_array( $options ) ? $options : array() ),
			'visible'   => $attribute->get_visible(),
			'variation' => $attribute->get_variation(),
			'position'  => $attribute->get_position(),
		);
	}

	return array(
		'product_id'        => $product->get_id(),
		'type'              => $product->get_type(),
		'status'            => $product->get_status(),
		'name'              => $product->get_name(),
		'slug'              => $product->get_slug(),
		'sku'               => $product->get_sku(),
		'regular_price'     => $product->get_regular_price(),
		'sale_price'        => $product->get_sale_price(),
		'price'             => $product->get_price(),
		'stock_quantity'    => $product->get_stock_quantity(),
		'manage_stock'      => (bool) $product->get_manage_stock(),
		'stock_status'      => $product->get_stock_status(),
		'short_description' => $product->get_short_description(),
		'description'       => $product->get_description(),
		'virtual'           => $product->get_virtual(),
		'downloadable'      => $product->get_downloadable(),
		'featured'          => $product->get_featured(),
		'catalog_visibility'=> $product->get_catalog_visibility(),
		'weight'            => $product->get_weight(),
		'dimensions'        => array(
			'length' => $product->get_length(),
			'width'  => $product->get_width(),
			'height' => $product->get_height(),
		),
		'image_id'          => $product->get_image_id(),
		'gallery_image_ids' => array_values( array_map( 'intval', $product->get_gallery_image_ids() ) ),
		'category_ids'      => array_values( array_map( 'intval', $product->get_category_ids() ) ),
		'tag_ids'           => array_values( array_map( 'intval', $product->get_tag_ids() ) ),
		'shipping_class_id' => (int) $product->get_shipping_class_id(),
		'attributes'        => $attributes,
	);
}

/**
 * @return array<string, mixed>
 */
function wpagent_wc_variation_payload( WC_Product_Variation $variation ): array {
	return array(
		'variation_id'  => $variation->get_id(),
		'parent_id'     => $variation->get_parent_id(),
		'status'        => $variation->get_status(),
		'sku'           => $variation->get_sku(),
		'regular_price' => $variation->get_regular_price(),
		'sale_price'    => $variation->get_sale_price(),
		'price'         => $variation->get_price(),
		'manage_stock'  => (bool) $variation->get_manage_stock(),
		'stock_quantity'=> $variation->get_stock_quantity(),
		'stock_status'  => $variation->get_stock_status(),
		'virtual'       => $variation->get_virtual(),
		'downloadable'  => $variation->get_downloadable(),
		'weight'        => $variation->get_weight(),
		'dimensions'    => array(
			'length' => $variation->get_length(),
			'width'  => $variation->get_width(),
			'height' => $variation->get_height(),
		),
		'image_id'       => $variation->get_image_id(),
		'description'    => $variation->get_description(),
		'attributes'     => $variation->get_attributes(),
	);
}

/**
 * Liefert einen stabil vergleichbaren Produktwert direkt aus dem Objekt.
 *
 * @return mixed
 */
function wpagent_wc_product_field_value( WC_Product $product, string $field ) {
	if ( 'attributes' === $field ) {
		$result = array();
		foreach ( $product->get_attributes() as $attribute ) {
			if ( $attribute instanceof WC_Product_Attribute ) {
				$result[] = array(
					'id'        => (int) $attribute->get_id(),
					'name'      => $attribute->get_name(),
					'options'   => array_values( $attribute->get_options() ),
					'visible'   => $attribute->get_visible(),
					'variation' => $attribute->get_variation(),
					'position'  => $attribute->get_position(),
				);
			}
		}
		return $result;
	}
	$getter = 'get_' . $field;
	return is_callable( array( $product, $getter ) ) ? $product->{$getter}() : null;
}

/**
 * @param list<string> $fields
 * @return array<string,mixed>
 */
function wpagent_wc_capture_product_fields( WC_Product $product, array $fields ): array {
	$result = array();
	foreach ( $fields as $field ) {
		$result[ $field ] = wpagent_wc_product_field_value( $product, $field );
	}
	return $result;
}

/**
 * @param array<string,mixed> $expected
 * @return array{written:array<string,bool>,verified:bool}
 */
function wpagent_wc_verify_product_fields( WC_Product $product, array $expected ): array {
	$written  = array();
	$verified = true;
	foreach ( $expected as $field => $value ) {
		$actual            = wpagent_wc_product_field_value( $product, $field );
		$ok                = $actual === $value;
		$written[ $field ] = $ok;
		$verified          = $verified && $ok;
	}
	return array( 'written' => $written, 'verified' => $verified );
}

/**
 * Liefert einen stabil vergleichbaren Variantenwert direkt aus dem Objekt.
 * Variantenattribute sind einfache Schlüssel-Wert-Paare und unterscheiden
 * sich damit von den WC_Product_Attribute-Objekten eines Elternprodukts.
 *
 * @return mixed
 */
function wpagent_wc_variation_field_value( WC_Product_Variation $variation, string $field ) {
	if ( 'attributes' === $field ) {
		return $variation->get_attributes();
	}
	$getter = 'get_' . $field;
	return is_callable( array( $variation, $getter ) ) ? $variation->{$getter}() : null;
}

/**
 * @param list<string> $fields
 * @return array<string,mixed>
 */
function wpagent_wc_capture_variation_fields( WC_Product_Variation $variation, array $fields ): array {
	$result = array();
	foreach ( $fields as $field ) {
		$result[ $field ] = wpagent_wc_variation_field_value( $variation, $field );
	}
	return $result;
}

/**
 * @param array<string,mixed> $expected
 * @return array{written:array<string,bool>,verified:bool}
 */
function wpagent_wc_verify_variation_fields( WC_Product_Variation $variation, array $expected ): array {
	$written  = array();
	$verified = true;
	foreach ( $expected as $field => $value ) {
		$actual            = wpagent_wc_variation_field_value( $variation, $field );
		$ok                = $actual === $value;
		$written[ $field ] = $ok;
		$verified          = $verified && $ok;
	}
	return array( 'written' => $written, 'verified' => $verified );
}

/**
 * @return true|WP_Error
 */
function wpagent_wc_validate_image_id( int $image_id, string $field ) {
	if ( 0 === $image_id ) {
		return true;
	}
	if ( $image_id < 0 || ! wp_attachment_is_image( $image_id ) ) {
		return new WP_Error(
			'wpagent_bad_product_value',
			sprintf(
				/* translators: %s: Feldname. */
				__( '%s muss auf einen vorhandenen Bildanhang zeigen.', 'wp-agent-companion' ),
				$field
			),
			array( 'status' => 400 )
		);
	}
	return true;
}

/**
 * @return true|WP_Error
 */
function wpagent_wc_require_assign_terms( string $taxonomy ) {
	$taxonomy_object = get_taxonomy( $taxonomy );
	if ( ! $taxonomy_object ) {
		return new WP_Error( 'wpagent_bad_product_value', __( 'Die angeforderte Produkttaxonomie ist nicht verfügbar.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$capability = $taxonomy_object->cap->assign_terms ?? 'edit_posts';
	if ( ! current_user_can( $capability ) ) {
		return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung zum Zuweisen dieser Produkttaxonomie.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	}
	return true;
}

/**
 * @param mixed  $raw
 * @param string $field
 * @return string|WP_Error
 */
function wpagent_sanitize_wc_price( $raw, string $field ) {
	if ( null === $raw || '' === $raw ) {
		return '';
	}
	if ( ! is_numeric( $raw ) || (float) $raw < 0 ) {
		return new WP_Error( 'wpagent_bad_product_value', sprintf( /* translators: %s: Feldname. */ __( '%s muss eine nicht negative Zahl sein.', 'wp-agent-companion' ), $field ), array( 'status' => 400 ) );
	}
	return (string) $raw;
}

/**
 * @param mixed  $raw
 * @param string $field
 * @return string|WP_Error
 */
function wpagent_sanitize_wc_dimension( $raw, string $field ) {
	if ( null === $raw || '' === $raw ) {
		return '';
	}
	if ( ! is_numeric( $raw ) || (float) $raw < 0 ) {
		return new WP_Error( 'wpagent_bad_product_value', sprintf( /* translators: %s: Feldname. */ __( '%s muss eine nicht negative Zahl sein.', 'wp-agent-companion' ), $field ), array( 'status' => 400 ) );
	}
	return (string) $raw;
}

/**
 * @param mixed $raw
 * @return list<WC_Product_Attribute>|WP_Error
 */
function wpagent_wc_build_attributes( $raw ) {
	if ( ! is_array( $raw ) ) {
		return new WP_Error( 'wpagent_bad_attributes', __( 'attributes muss eine Liste sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	}
	$result = array();
	$seen   = array();
	foreach ( array_values( $raw ) as $position => $item ) {
		if ( ! is_array( $item ) ) {
			return new WP_Error( 'wpagent_bad_attributes', __( 'Jedes Attribut muss ein Objekt sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$name = trim( (string) ( $item['name'] ?? '' ) );
		if ( '' === $name || ! isset( $item['options'] ) || ! is_array( $item['options'] ) || array() === $item['options'] ) {
			return new WP_Error( 'wpagent_bad_attributes', __( 'Jedes Attribut benötigt name und mindestens eine Option.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$taxonomy = wc_attribute_taxonomy_name( $name );
		$is_global = taxonomy_exists( $name ) || taxonomy_exists( $taxonomy );
		$attribute_name = $is_global ? ( taxonomy_exists( $name ) ? $name : $taxonomy ) : $name;
		$key = sanitize_title( $attribute_name );
		if ( isset( $seen[ $key ] ) ) {
			return new WP_Error( 'wpagent_bad_attributes', sprintf( /* translators: %s: Attributname. */ __( 'Das Attribut "%s" wurde doppelt übergeben.', 'wp-agent-companion' ), $name ), array( 'status' => 400 ) );
		}
		$seen[ $key ] = true;

		$options = array_values( array_unique( array_filter( array_map( 'strval', $item['options'] ), static fn( string $value ): bool => '' !== trim( $value ) ) ) );
		if ( array() === $options ) {
			return new WP_Error( 'wpagent_bad_attributes', sprintf( /* translators: %s: Attributname. */ __( 'Das Attribut "%s" enthält keine gültige Option.', 'wp-agent-companion' ), $name ), array( 'status' => 400 ) );
		}
		if ( $is_global ) {
			$allowed = wpagent_wc_require_assign_terms( $attribute_name );
			if ( is_wp_error( $allowed ) ) {
				return $allowed;
			}
			$term_ids = array();
			foreach ( $options as $option ) {
				$term = ctype_digit( $option ) ? get_term( (int) $option, $attribute_name ) : get_term_by( 'slug', sanitize_title( $option ), $attribute_name );
				if ( ! $term || is_wp_error( $term ) ) {
					$term = get_term_by( 'name', $option, $attribute_name );
				}
				if ( ! $term || is_wp_error( $term ) ) {
					return new WP_Error( 'wpagent_bad_attributes', sprintf( /* translators: 1: Option, 2: Attribut-Taxonomie. */ __( 'Die Option "%1$s" existiert nicht in der globalen Attribut-Taxonomie "%2$s".', 'wp-agent-companion' ), $option, $attribute_name ), array( 'status' => 400 ) );
				}
				$term_ids[] = (int) $term->term_id;
			}
			$options = array_values( array_unique( $term_ids ) );
		}
		$attribute = new WC_Product_Attribute();
		$attribute->set_id( $is_global ? (int) wc_attribute_taxonomy_id_by_name( $attribute_name ) : 0 );
		$attribute->set_name( $attribute_name );
		$attribute->set_options( $options );
		$attribute->set_position( $position );
		$attribute->set_visible( (bool) ( $item['visible'] ?? true ) );
		$attribute->set_variation( (bool) ( $item['variation'] ?? false ) );
		$result[] = $attribute;
	}
	return $result;
}

/**
 * @return true|WP_Error
 */
function wpagent_wc_validate_sku( string $sku, int $current_id = 0 ) {
	if ( '' === $sku ) {
		return true;
	}
	$existing_id = wc_get_product_id_by_sku( $sku );
	if ( $existing_id > 0 && $existing_id !== $current_id ) {
		return new WP_Error( 'wpagent_sku_collision', sprintf( /* translators: 1: SKU, 2: Produkt-ID. */ __( 'Die SKU "%1$s" wird bereits von Produkt #%2$d verwendet.', 'wp-agent-companion' ), $sku, $existing_id ), array( 'status' => 400 ) );
	}
	return true;
}
