<?php
/**
 * Abilities für WooCommerce-Produktvarianten.
 *
 * @package WPAgentCompanion
 */

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

function wpagent_ability_list_product_variations(): array {
	return array(
		'label' => __( 'Produktvarianten auflisten', 'wp-agent-companion' ), 'description' => __( 'Listet die Varianten eines variablen WooCommerce-Produkts auf.', 'wp-agent-companion' ), 'category' => 'wp-agent',
		'input_schema' => array( 'type' => 'object', 'properties' => array( 'product_id' => array( 'type' => 'integer' ) ), 'required' => array( 'product_id' ) ),
		'output_schema' => array( 'type' => 'object', 'properties' => array( 'variations' => array( 'type' => 'array' ), 'total' => array( 'type' => 'integer' ) ) ),
		'execute_callback' => 'wpagent_exec_list_product_variations', 'permission_callback' => 'wpagent_perm_edit_posts',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => true, 'destructive' => false, 'idempotent' => true ) ),
	);
}

function wpagent_ability_upsert_product_variation(): array {
	return array(
		'label' => __( 'Produktvariante anlegen oder aktualisieren', 'wp-agent-companion' ), 'description' => __( 'Legt eine Produktvariante an oder aktualisiert sie über WC_Product_Variation und verifiziert das Ergebnis.', 'wp-agent-companion' ), 'category' => 'wp-agent',
		'input_schema' => array( 'type' => 'object', 'properties' => array(
			'product_id' => array( 'type' => 'integer' ), 'variation_id' => array( 'type' => 'integer' ), 'attributes' => array( 'type' => 'object' ),
			'status' => array( 'type' => 'string', 'enum' => array( 'draft', 'publish', 'private' ) ), 'sku' => array( 'type' => 'string' ), 'regular_price' => array( 'type' => 'string' ), 'sale_price' => array( 'type' => 'string' ),
			'manage_stock' => array( 'type' => 'boolean' ), 'stock_quantity' => array( 'type' => 'integer' ), 'stock_status' => array( 'type' => 'string', 'enum' => array( 'instock', 'outofstock', 'onbackorder' ) ),
			'virtual' => array( 'type' => 'boolean' ), 'downloadable' => array( 'type' => 'boolean' ), 'weight' => array( 'type' => 'string' ), 'length' => array( 'type' => 'string' ), 'width' => array( 'type' => 'string' ), 'height' => array( 'type' => 'string' ), 'image_id' => array( 'type' => 'integer', 'minimum' => 0 ), 'description' => array( 'type' => 'string' ),
		), 'required' => array( 'product_id' ) ),
		'output_schema' => array( 'type' => 'object', 'properties' => array( 'variation' => array( 'type' => 'object' ), 'written' => array( 'type' => 'object' ), 'verified' => array( 'type' => 'boolean' ) ) ),
		'execute_callback' => 'wpagent_exec_upsert_product_variation', 'permission_callback' => 'wpagent_perm_edit_posts',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => false, 'idempotent' => true ) ),
	);
}

function wpagent_ability_delete_product_variation(): array {
	return array(
		'label' => __( 'Produktvariante endgültig löschen', 'wp-agent-companion' ), 'description' => __( 'Löscht eine Produktvariante endgültig. confirm=true ist zwingend erforderlich.', 'wp-agent-companion' ), 'category' => 'wp-agent',
		'input_schema' => array( 'type' => 'object', 'properties' => array( 'product_id' => array( 'type' => 'integer' ), 'variation_id' => array( 'type' => 'integer' ), 'confirm' => array( 'type' => 'boolean' ) ), 'required' => array( 'product_id', 'variation_id', 'confirm' ) ),
		'output_schema' => array( 'type' => 'object', 'properties' => array( 'variation_id' => array( 'type' => 'integer' ), 'deleted' => array( 'type' => 'boolean' ) ) ),
		'execute_callback' => 'wpagent_exec_delete_product_variation', 'permission_callback' => 'wpagent_perm_edit_posts',
		'meta' => array( 'show_in_rest' => true, 'annotations' => array( 'readonly' => false, 'destructive' => true, 'idempotent' => false ) ),
	);
}

/** @return WC_Product_Variable|WP_Error */
function wpagent_get_editable_variable_product( int $product_id ) {
	$product = wpagent_get_editable_product( $product_id );
	if ( is_wp_error( $product ) ) return $product;
	if ( ! $product instanceof WC_Product_Variable ) return new WP_Error( 'wpagent_not_variable', __( 'Das Produkt ist kein variables Produkt.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	return $product;
}

/** @return array|WP_Error */
function wpagent_exec_list_product_variations( $input ) {
	$input = is_array( $input ) ? $input : array();
	$product = wpagent_get_editable_variable_product( (int) ( $input['product_id'] ?? 0 ) );
	if ( is_wp_error( $product ) ) return $product;
	$variations = array();
	foreach ( $product->get_children() as $variation_id ) {
		$variation = wc_get_product( $variation_id );
		if ( $variation instanceof WC_Product_Variation ) $variations[] = wpagent_wc_variation_payload( $variation );
	}
	return array( 'variations' => $variations, 'total' => count( $variations ) );
}

/** @return array|WP_Error */
function wpagent_exec_upsert_product_variation( $input ) {
	$input = is_array( $input ) ? $input : array();
	$product_id = (int) ( $input['product_id'] ?? 0 );
	$parent = wpagent_get_editable_variable_product( $product_id );
	if ( is_wp_error( $parent ) ) return $parent;
	$variation_id = (int) ( $input['variation_id'] ?? 0 );
	$creating = 0 === $variation_id;
	if ( $variation_id > 0 ) {
		$variation = wc_get_product( $variation_id );
		if ( ! $variation instanceof WC_Product_Variation || $variation->get_parent_id() !== $product_id ) return new WP_Error( 'wpagent_no_variation', __( 'Produktvariante nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	} else {
		if ( ! isset( $input['attributes'] ) || ! is_array( $input['attributes'] ) || array() === $input['attributes'] ) return new WP_Error( 'wpagent_bad_attributes', __( 'Eine neue Variante benötigt mindestens ein Attribut.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		$variation = new WC_Product_Variation();
		$variation->set_parent_id( $product_id );
	}
	$changed = array();
	try {
		if ( array_key_exists( 'attributes', $input ) ) {
			$attributes = wpagent_wc_normalize_variation_attributes( $parent, $input['attributes'] );
			if ( is_wp_error( $attributes ) ) return $attributes;
			$variation->set_attributes( $attributes );
			$changed[] = 'attributes';
		}
		if ( array_key_exists( 'sku', $input ) ) {
			$sku = (string) $input['sku'];
			$valid = wpagent_wc_validate_sku( $sku, $variation_id );
			if ( is_wp_error( $valid ) ) return $valid;
			$variation->set_sku( $sku );
			$changed[] = 'sku';
		}
		foreach ( array( 'regular_price', 'sale_price' ) as $field ) {
			if ( ! array_key_exists( $field, $input ) ) continue;
			$value = wpagent_sanitize_wc_price( $input[ $field ], $field );
			if ( is_wp_error( $value ) ) return $value;
			$variation->{'set_' . $field}( $value );
			$changed[] = $field;
		}
		foreach ( array( 'weight', 'length', 'width', 'height' ) as $field ) {
			if ( ! array_key_exists( $field, $input ) ) continue;
			$value = wpagent_sanitize_wc_dimension( $input[ $field ], $field );
			if ( is_wp_error( $value ) ) return $value;
			$variation->{'set_' . $field}( $value );
			$changed[] = $field;
		}
		foreach ( array( 'manage_stock', 'virtual', 'downloadable' ) as $field ) {
			if ( ! array_key_exists( $field, $input ) ) continue;
			$variation->{'set_' . $field}( (bool) $input[ $field ] );
			$changed[] = $field;
		}
		if ( array_key_exists( 'stock_quantity', $input ) ) {
			$variation->set_stock_quantity( (int) $input['stock_quantity'] );
			$changed[] = 'stock_quantity';
		}
		if ( array_key_exists( 'stock_status', $input ) ) {
			$variation->set_stock_status( (string) $input['stock_status'] );
			$changed[] = 'stock_status';
		}
		if ( array_key_exists( 'image_id', $input ) ) {
			$image_id = (int) $input['image_id'];
			$valid = wpagent_wc_validate_image_id( $image_id, 'image_id' );
			if ( is_wp_error( $valid ) ) return $valid;
			$variation->set_image_id( $image_id );
			$changed[] = 'image_id';
		}
		if ( array_key_exists( 'description', $input ) ) {
			$variation->set_description( (string) $input['description'] );
			$changed[] = 'description';
		}
		$status = array_key_exists( 'status', $input ) ? (string) $input['status'] : ( $creating ? 'draft' : null );
		if ( null !== $status ) {
			$status_cap = wpagent_check_post_status_cap( 'product', $status );
			if ( is_wp_error( $status_cap ) ) return $status_cap;
			$variation->set_status( $status );
			$changed[] = 'status';
		}
		if ( ! $creating && array() === $changed ) {
			return new WP_Error( 'wpagent_no_fields', __( 'Kein zu aktualisierendes Feld übergeben.', 'wp-agent-companion' ), array( 'status' => 400 ) );
		}
		$verify_fields = $creating ? array_values( array_unique( array_merge( array( 'parent_id' ), $changed ) ) ) : $changed;
		$expected = wpagent_wc_capture_variation_fields( $variation, $verify_fields );
		$variation_id = $variation->save();
	} catch ( WC_Data_Exception $e ) {
		return new WP_Error( 'wpagent_wc_invalid', $e->getMessage(), array( 'status' => 400 ) );
	}
	WC_Product_Variable::sync( $product_id );
	wc_delete_product_transients( $product_id );
	$fresh = wc_get_product( $variation_id );
	if ( ! $fresh instanceof WC_Product_Variation ) {
		return new WP_Error( 'wpagent_wc_readback_failed', __( 'Die Produktvariante konnte nicht erneut gelesen werden.', 'wp-agent-companion' ), array( 'status' => 500 ) );
	}
	$verification = wpagent_wc_verify_variation_fields( $fresh, $expected );
	return array(
		'variation' => wpagent_wc_variation_payload( $fresh ),
		'written'   => $verification['written'],
		'verified'  => $verification['verified'],
	);
}

/** @return array|WP_Error */
function wpagent_exec_delete_product_variation( $input ) {
	$input = is_array( $input ) ? $input : array();
	$product_id = (int) ( $input['product_id'] ?? 0 ); $variation_id = (int) ( $input['variation_id'] ?? 0 );
	$parent = wpagent_get_editable_variable_product( $product_id ); if ( is_wp_error( $parent ) ) return $parent;
	$variation = wc_get_product( $variation_id );
	if ( ! $variation instanceof WC_Product_Variation || $variation->get_parent_id() !== $product_id ) return new WP_Error( 'wpagent_no_variation', __( 'Produktvariante nicht gefunden.', 'wp-agent-companion' ), array( 'status' => 404 ) );
	if ( ! current_user_can( 'delete_post', $variation_id ) ) return new WP_Error( 'wpagent_forbidden', __( 'Keine Berechtigung.', 'wp-agent-companion' ), array( 'status' => 403 ) );
	if ( true !== ( $input['confirm'] ?? false ) ) return new WP_Error( 'wpagent_confirmation_required', __( 'Zum endgültigen Löschen ist confirm=true erforderlich.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	$deleted = $variation->delete( true ); WC_Product_Variable::sync( $product_id ); wc_delete_product_transients( $product_id ); clean_post_cache( $variation_id );
	return array( 'variation_id' => $variation_id, 'deleted' => true === $deleted && null === get_post( $variation_id ) );
}

/** @return array<string, string>|WP_Error */
function wpagent_wc_normalize_variation_attributes( WC_Product_Variable $parent, $raw ) {
	if ( ! is_array( $raw ) ) return new WP_Error( 'wpagent_bad_attributes', __( 'attributes muss ein Objekt sein.', 'wp-agent-companion' ), array( 'status' => 400 ) );
	$definitions = array();
	foreach ( $parent->get_attributes() as $attribute ) {
		if ( ! $attribute instanceof WC_Product_Attribute || ! $attribute->get_variation() ) continue;
		$key = $attribute->is_taxonomy() ? $attribute->get_name() : sanitize_title( $attribute->get_name() );
		$options = $attribute->is_taxonomy() ? wc_get_product_terms( $parent->get_id(), $attribute->get_name(), array( 'fields' => 'slugs' ) ) : array_map( 'sanitize_title', $attribute->get_options() );
		$definitions[ sanitize_title( $key ) ] = array( 'key' => $key, 'options' => $options );
	}
	$result = array();
	foreach ( $raw as $raw_key => $raw_value ) {
		$lookup = sanitize_title( (string) $raw_key );
		if ( ! isset( $definitions[ $lookup ] ) ) return new WP_Error( 'wpagent_bad_attributes', sprintf( /* translators: %s: Attributname. */ __( 'Das Variantenattribut "%s" ist am Elternprodukt nicht freigegeben.', 'wp-agent-companion' ), (string) $raw_key ), array( 'status' => 400 ) );
		$value = sanitize_title( (string) $raw_value );
		if ( '' !== $value && ! in_array( $value, $definitions[ $lookup ]['options'], true ) ) return new WP_Error( 'wpagent_bad_attributes', sprintf( /* translators: %s: Attributwert. */ __( 'Der Attributwert "%s" ist am Elternprodukt nicht vorhanden.', 'wp-agent-companion' ), (string) $raw_value ), array( 'status' => 400 ) );
		$result[ $definitions[ $lookup ]['key'] ] = $value;
	}
	return $result;
}
