<?php

namespace Fotogenic_AI;

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

/**
 * Strict raw-JSON decoder for universal result mutations.
 *
 * WordPress REST schema validation intentionally coerces compatible scalar
 * values. Result mutations must preserve the exact browser-to-WordPress JSON
 * contract before any service normalization occurs.
 */
final class Rest_Result_Request_Decoder {
	private const WORKFLOWS = [ 'product_images', 'campaign_set', 'increase_resolution' ];
	private const SOURCES   = [ 'product', 'media', 'post', 'page' ];
	private const ACTIONS   = [ 'apply_featured', 'apply_gallery', 'apply_both', 'add_selected_to_gallery', 'add_all_to_gallery' ];

	/**
	 * @return array<string,mixed>|\WP_Error
	 */
	public static function decode( \WP_REST_Request $request, bool $require_action, int $maximum_attachments ) {
		$content_type = $request->get_content_type();
		if ( ! is_array( $content_type ) || 'application/json' !== (string) ( $content_type['value'] ?? '' ) ) {
			return self::error( 'fotogenic_ai_result_content_type_invalid', __( 'The result mutation requires a JSON request body.', 'fotogenic-ai' ), 415 );
		}

		$body = $request->get_body();
		if ( ! is_string( $body ) || '' === trim( $body ) ) {
			return self::invalid_payload();
		}
		try {
			$decoded = json_decode( $body, false, 32, JSON_THROW_ON_ERROR );
		} catch ( \JsonException $exception ) {
			unset( $exception );
			return self::invalid_payload();
		}
		if ( ! ( $decoded instanceof \stdClass ) ) {
			return self::invalid_payload();
		}

		$payload  = get_object_vars( $decoded );
		$expected = [ 'runId', 'requestId', 'workflow', 'sourceType', 'scope', 'subjectId', 'attachmentIds' ];
		$item_identity_fields = [ 'runItemId', 'campaignGroupId', 'itemOrdinal', 'targetIdentity' ];
		$has_item_identity = ! empty( array_intersect( $item_identity_fields, array_keys( $payload ) ) );
		if ( $has_item_identity ) {
			$expected = array_merge( $expected, $item_identity_fields );
		}
		$scope    = is_string( $payload['scope'] ?? null ) ? $payload['scope'] : '';
		if ( 'bulk' === $scope ) {
			$expected[] = 'bulkRunUuid';
			$expected[] = 'bulkItemId';
		}
		if ( $require_action ) {
			$expected[] = 'action';
		}
		$keys = array_keys( $payload );
		sort( $keys, SORT_STRING );
		sort( $expected, SORT_STRING );
		if ( $keys !== $expected ) {
			return self::invalid_payload();
		}

		if (
			! is_string( $payload['runId'] )
			|| '' === $payload['runId']
			|| strlen( $payload['runId'] ) > 64
			|| ! is_string( $payload['requestId'] )
			|| ! wp_is_uuid( strtolower( trim( $payload['requestId'] ) ) )
			|| ! is_string( $payload['workflow'] )
			|| ! in_array( $payload['workflow'], self::WORKFLOWS, true )
			|| ! is_string( $payload['sourceType'] )
			|| ! in_array( $payload['sourceType'], self::SOURCES, true )
			|| ! is_string( $payload['scope'] )
			|| ! in_array( $scope, [ 'single', 'bulk' ], true )
			|| ! is_int( $payload['subjectId'] )
			|| $payload['subjectId'] < 1
			|| ! is_array( $payload['attachmentIds'] )
			|| ! fotogenic_ai_array_is_list( $payload['attachmentIds'] )
			|| count( $payload['attachmentIds'] ) < 1
			|| count( $payload['attachmentIds'] ) > $maximum_attachments
		) {
			return self::invalid_payload();
		}
		if ( $has_item_identity ) {
			$target = $payload['targetIdentity'] ?? null;
			$target = $target instanceof \stdClass ? get_object_vars( $target ) : null;
			if (
				! is_string( $payload['runItemId'] )
				|| ! wp_is_uuid( strtolower( trim( $payload['runItemId'] ) ) )
				|| ( null !== $payload['campaignGroupId'] && ( ! is_string( $payload['campaignGroupId'] ) || ! wp_is_uuid( strtolower( trim( $payload['campaignGroupId'] ) ) ) ) )
				|| ! is_int( $payload['itemOrdinal'] )
				|| $payload['itemOrdinal'] < 1
				|| ! is_array( $target )
				|| [ 'targetType', 'targetId', 'parentProductId', 'variationId' ] !== array_keys( $target )
				|| ! is_string( $target['targetType'] )
				|| ! in_array( $target['targetType'], [ 'product', 'variation', 'media', 'post', 'page' ], true )
				|| ! is_int( $target['targetId'] )
				|| $target['targetId'] !== $payload['subjectId']
				|| ! is_int( $target['parentProductId'] )
				|| $target['parentProductId'] < 0
				|| ! is_int( $target['variationId'] )
				|| $target['variationId'] < 0
				|| ( 'campaign_set' === $payload['workflow'] ? null === $payload['campaignGroupId'] : null !== $payload['campaignGroupId'] )
				|| ( 'single' === $scope && 1 !== $payload['itemOrdinal'] )
				|| ( 'product' === $payload['sourceType'] && ! in_array( $target['targetType'], [ 'product', 'variation' ], true ) )
				|| ( 'product' !== $payload['sourceType'] && $target['targetType'] !== $payload['sourceType'] )
				|| ( 'variation' === $target['targetType'] && ( $target['variationId'] !== $target['targetId'] || $target['parentProductId'] < 1 ) )
				|| ( 'variation' !== $target['targetType'] && ( 0 !== $target['variationId'] || 0 !== $target['parentProductId'] ) )
			) {
				return self::invalid_payload();
			}
			$payload['runItemId'] = strtolower( trim( $payload['runItemId'] ) );
			$payload['campaignGroupId'] = is_string( $payload['campaignGroupId'] )
				? strtolower( trim( $payload['campaignGroupId'] ) )
				: null;
			$payload['targetIdentity'] = $target;
		}
		if (
			'bulk' === $scope
			&& (
				! is_string( $payload['bulkRunUuid'] )
				|| ! wp_is_uuid( strtolower( trim( $payload['bulkRunUuid'] ) ) )
				|| ! is_int( $payload['bulkItemId'] )
				|| $payload['bulkItemId'] < 1
			)
		) {
			return self::invalid_payload();
		}
		foreach ( $payload['attachmentIds'] as $attachment_id ) {
			if ( ! is_int( $attachment_id ) || $attachment_id < 1 ) {
				return self::invalid_payload();
			}
		}
		if ( count( array_unique( $payload['attachmentIds'] ) ) !== count( $payload['attachmentIds'] ) ) {
			return self::invalid_payload();
		}
		if ( $require_action && ( ! is_string( $payload['action'] ) || ! in_array( $payload['action'], self::ACTIONS, true ) ) ) {
			return self::invalid_payload();
		}

		return $payload;
	}

	private static function invalid_payload(): \WP_Error {
		return self::error(
			'fotogenic_ai_result_payload_invalid',
			__( 'The result mutation payload is invalid.', 'fotogenic-ai' ),
			400
		);
	}

	private static function error( string $code, string $message, int $status ): \WP_Error {
		return new \WP_Error( $code, $message, [ 'status' => $status ] );
	}
}
