<?php

namespace Fotogenic_AI;

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

final class Service_Generate_Start {
    private const WORKFLOW = 'product_images';

	/** @return array|\WP_Error */
	public function start_command( int $user_id, array $command, array $options = [] ) {
		$allowed_fields = [
			'requestId', 'target', 'subjectId', 'customInstructions', 'imagesCount', 'quality', 'style',
			'applyGlobalInstructions', 'autoConfigUsed', 'autoConfigDescription', 'personPresence',
			'includeFace', 'includeBody', 'lookAtCamera', 'selections', 'subjectImageId',
			'inspirationImageId', 'environmentImageId', 'galleryImageIds', 'excludeFeatured',
		];
		if ( $user_id <= 0 || get_current_user_id() !== $user_id ) {
			return Messages::error( 'forbidden', 403 );
		}
		if ( ! empty( array_diff( array_keys( $command ), $allowed_fields ) ) ) {
			return Messages::error( 'invalid_request', 400 );
		}
		$universal_fingerprint = (string) ( $options['universal_fingerprint'] ?? '' );
		$trusted_item_context  = (array) ( $options['item_identity'] ?? [] );
		$trusted_pricing       = (array) ( $options['trusted_pricing'] ?? [] );
		$bulk_run_uuid         = strtolower( trim( (string) ( $options['bulk_run_uuid'] ?? '' ) ) );
		$bulk_item_id          = (int) ( $options['bulk_item_id'] ?? 0 );
        $coordinator = new Workflow_Start_Coordinator();
		$request_id = $coordinator->validate_request_id( (string) ( $command['requestId'] ?? '' ) );
        if ( is_wp_error( $request_id ) ) {
            return $request_id;
        }
		$target = sanitize_key( (string) ( $command['target'] ?? '' ) );
        $is_bulk_context = $bulk_run_uuid !== '' && $bulk_item_id > 0;
		$subject_id = (int) ( $command['subjectId'] ?? 0 );
        $product_id = ( 'product' === $target ) ? $subject_id : 0;
        $media_id = ( 'media' === $target ) ? $subject_id : 0;

        $settings = Settings::instance();
        $options = $settings->get_options();
        $auto_configure = ! empty( $options['auto_configure'] ?? false );

		$custom_instructions = (string) ( $command['customInstructions'] ?? '' );
		$style              = sanitize_text_field( (string) ( $command['style'] ?? '' ) );
		$images_count = (int) ( $command['imagesCount'] ?? 0 );
        if ( $images_count < 1 || $images_count > 6 ) {
            $images_count = 1;
        }
		$quality = strtoupper( trim( (string) ( $command['quality'] ?? '' ) ) );
        if ( '' === $quality ) {
            $quality = '2K';
        }
        if ( ! Workflow_Quality_Catalog::supports( 'product_images', $quality ) ) {
            return new \WP_Error(
                'fotogenic_ai_quality_unavailable',
                __( 'The selected image quality is unavailable for Generate Images.', 'fotogenic-ai' ),
                [ 'status' => 409 ]
            );
        }
		$apply_global_param = $command['applyGlobalInstructions'] ?? null;
        $apply_global_instructions = null === $apply_global_param ? true : rest_sanitize_boolean( $apply_global_param );
		$auto_config_used_param = $command['autoConfigUsed'] ?? false;
        $auto_config_used = rest_sanitize_boolean( $auto_config_used_param );
		$auto_config_description = sanitize_textarea_field( (string) ( $command['autoConfigDescription'] ?? '' ) );
        if ( ! $auto_config_used ) {
            $auto_config_description = '';
        }
		$person_presence_param = $command['personPresence'] ?? null;
        $person_presence = null;
        if ( null !== $person_presence_param && '' !== $person_presence_param && 'auto' !== $person_presence_param ) {
            $person_presence = rest_sanitize_boolean( $person_presence_param );
        }
		$include_face_param = $command['includeFace'] ?? null;
        $include_face = null;
        if ( null !== $include_face_param && '' !== $include_face_param && 'auto' !== $include_face_param ) {
            $include_face = rest_sanitize_boolean( $include_face_param );
        }
		$include_body_param = $command['includeBody'] ?? null;
        $include_body = null;
        if ( null !== $include_body_param && '' !== $include_body_param && 'auto' !== $include_body_param ) {
            $include_body = rest_sanitize_boolean( $include_body_param );
        }
		$look_at_camera_param = $command['lookAtCamera'] ?? null;
        $look_at_camera = null;
        if ( null !== $look_at_camera_param && '' !== $look_at_camera_param && 'auto' !== $look_at_camera_param ) {
            $look_at_camera = rest_sanitize_boolean( $look_at_camera_param );
        }

        $is_attachment_target = in_array( $target, [ 'media', 'post', 'page' ], true ) && $subject_id > 0;
        $primary_attachment_id = 0;

        $product_title = '';
        $product_sku = '';
        if ( $is_attachment_target ) {
            if ( 'media' === $target ) {
                if ( ! current_user_can( 'upload_files' ) ) {
                    return Messages::error( 'forbidden', 403 );
                }
                if ( ! current_user_can( 'edit_post', $media_id ) ) {
                    return Messages::error( 'forbidden', 403 );
                }
                $media_post = get_post( $media_id );
                if ( ! $media_post || 'attachment' !== ( $media_post->post_type ?? '' ) ) {
                    return Messages::error( 'invalid_request', 404 );
                }
				$primary_attachment_id = $media_id;
            } else {
                if ( ! current_user_can( 'edit_post', $subject_id ) ) {
                    return Messages::error( 'forbidden', 403 );
                }
                $post = get_post( $subject_id );
                if ( ! $post ) {
                    return Messages::error( 'invalid_request', 404 );
                }
                $expected_type = 'post' === $target ? 'post' : 'page';
                if ( $expected_type !== ( $post->post_type ?? '' ) ) {
                    return Messages::error( 'invalid_request', 400 );
                }
				$primary_attachment_id = (int) get_post_thumbnail_id( $subject_id );
                if ( $primary_attachment_id <= 0 ) {
                    return new \WP_Error(
                        'fotogenic_ai_no_source_image',
                        __( 'This target needs a featured image before generation can run.', 'fotogenic-ai' ),
                        [ 'status' => 400 ]
                    );
                }
            }
        } else {
            if ( $product_id < 1 ) {
                return Messages::error( 'missing_product', 400 );
            }
            $product_query_adapter = Plugin::instance()->compat()->get_product_query_adapter();
            $product_summary = $product_query_adapter->get_product_summary( $product_id );
            if ( is_wp_error( $product_summary ) ) {
                $code   = $product_summary->get_error_code();
                $status = (int) ( $product_summary->get_error_data()['status'] ?? 503 );
                return Messages::error( 'woocommerce_not_active' === $code ? 'woocommerce_not_active' : 'missing_product', $status );
            }
            if ( null === $product_summary ) {
                return Messages::error( 'missing_product', 400 );
            }
            if ( ! current_user_can( 'edit_post', $product_id ) ) {
                return Messages::error( 'forbidden_product', 403 );
            }
			$product_sku = (string) ( $product_summary['sku'] ?? '' );
        }

		$subject_image_id = (int) ( $command['subjectImageId'] ?? 0 );
		$inspiration_image_id = (int) ( $command['inspirationImageId'] ?? 0 );
		$environment_image_id = (int) ( $command['environmentImageId'] ?? 0 );
        if ( $subject_image_id > 0 && ! current_user_can( 'edit_post', $subject_image_id ) ) {
            return Messages::error( 'forbidden_remove', 403 );
        }
        if ( $inspiration_image_id > 0 && ! current_user_can( 'edit_post', $inspiration_image_id ) ) {
            return Messages::error( 'forbidden_remove', 403 );
        }
        if ( $environment_image_id > 0 && ! current_user_can( 'edit_post', $environment_image_id ) ) {
            return Messages::error( 'forbidden_remove', 403 );
        }

        $run_target = $is_attachment_target ? $target : 'product';
        $subject_id = $is_attachment_target ? $subject_id : $product_id;

		$requested_gallery_ids = $command['galleryImageIds'] ?? null;
        $selected_gallery_ids = is_array( $requested_gallery_ids )
            ? array_values( array_unique( array_filter( array_map( 'absint', $requested_gallery_ids ) ) ) )
            : null;
		$exclude_featured = rest_sanitize_boolean( $command['excludeFeatured'] ?? false );
        $global_instructions = $apply_global_instructions
            ? trim( (string) ( $options['custom_instructions'] ?? '' ) )
            : '';
        $context = [
            'run_target' => $run_target,
            'subject_id' => $subject_id,
        ];
        $target_snapshot = Workflow_Item_Identity::resolve_target( $run_target, $subject_id );
		if ( is_wp_error( $target_snapshot ) ) {
			return $target_snapshot;
		}
		$product_title = (string) $target_snapshot['label'];
        $context['target_type'] = (string) $target_snapshot['targetType'];
        $context['parent_product_id'] = (int) $target_snapshot['parentProductId'];
        $context['variation_id'] = (int) $target_snapshot['variationId'];
        $context['target_snapshot'] = $target_snapshot;
        $context = $coordinator->attach_item_identity_context( $context, $trusted_item_context );
        if ( is_wp_error( $context ) ) {
            return $context;
        }
        $fingerprint_payload = [
                'target'                   => $run_target,
                'subjectId'                => $subject_id,
				'customInstructions'       => $custom_instructions,
				'style'                    => $style,
                'globalInstructions'       => $global_instructions,
                'imagesCount'              => $images_count,
                'quality'                  => $quality,
                'applyGlobalInstructions'  => $apply_global_instructions,
                'autoConfigure'             => $auto_configure,
                'autoConfigUsed'            => $auto_config_used,
                'autoConfigDescription'     => $auto_config_description,
                'personPresence'            => $person_presence,
                'includeFace'               => $include_face,
                'includeBody'               => $include_body,
                'lookAtCamera'              => $look_at_camera,
				'selections'                => $command['selections'] ?? [],
                'subjectImageId'            => $subject_image_id,
                'inspirationImageId'        => $inspiration_image_id,
                'environmentImageId'        => $environment_image_id,
                'galleryImageIds'           => $selected_gallery_ids,
                'excludeFeatured'           => $exclude_featured,
                'bulkRunUuid'               => $is_bulk_context ? $bulk_run_uuid : '',
                'bulkItemId'                => $is_bulk_context ? $bulk_item_id : 0,
        ];
        if ( ! empty( $context['run_item_uuid'] ) ) {
            $fingerprint_payload['itemIdentity'] = [
                'runItemId'       => (string) $context['run_item_uuid'],
                'campaignGroupId' => (string) ( $context['campaign_group_uuid'] ?? '' ),
                'itemOrdinal'     => (int) ( $context['item_ordinal'] ?? 0 ),
                'target'          => Workflow_Item_Identity::target_hint( (array) $context['target_snapshot'] ),
            ];
        }
        $fingerprint = $coordinator->fingerprint_payload( self::WORKFLOW, $fingerprint_payload );
        if ( is_wp_error( $fingerprint ) ) {
            return $fingerprint;
        }
        $replay = $coordinator->replay_request( $user_id, self::WORKFLOW, $request_id, $fingerprint );
        if ( null !== $replay ) {
            return $this->format_start_result( $replay );
        }
        $subject_guard = $coordinator->guard_subject_admission( $user_id, self::WORKFLOW, $request_id, $context );
        if ( is_wp_error( $subject_guard ) ) {
            return $subject_guard;
        }

        if ( $is_attachment_target ) {
            $primary_image = Image_Source_Resolver::instance()->get_image_file_for_attachment( $primary_attachment_id );
            if ( is_wp_error( $primary_image ) ) {
                return $primary_image;
            }
            $product_images = [ $primary_image ];

            $subject_image = $this->resolve_optional_image_file( $subject_image_id );
            if ( is_wp_error( $subject_image ) ) {
                return $subject_image;
            }

            $inspiration_image = $this->resolve_optional_image_file( $inspiration_image_id );
            if ( is_wp_error( $inspiration_image ) ) {
                return $inspiration_image;
            }

            $environment_image = $this->resolve_optional_image_file( $environment_image_id );
            if ( is_wp_error( $environment_image ) ) {
                return $environment_image;
            }
        } else {
            $image_source_adapter = Plugin::instance()->compat()->get_product_image_source_adapter();
            $image_builder = new Generate_Image_Builder();
            $images_payload = $image_builder->build_for_generate_start(
                $product_id,
                $image_source_adapter,
                $selected_gallery_ids,
                $subject_image_id,
                $inspiration_image_id,
                $environment_image_id,
                $run_target,
                $exclude_featured
            );
            if ( is_wp_error( $images_payload ) ) {
                return $images_payload;
            }
            $product_images = $images_payload['product_images'] ?? [];
            $subject_image = $images_payload['subject_image'] ?? '';
            $inspiration_image = $images_payload['inspiration_image'] ?? '';
            $environment_image = $images_payload['environment_image'] ?? '';
        }

        $config_result = null;

        $metadata = [
            'product_title' => $product_title,
            'product_sku'   => $product_sku,
            'run_target'    => $run_target,
            'subject_id'    => $subject_id,
            'user_id'       => $user_id,
            'bulk_run_uuid' => $is_bulk_context ? $bulk_run_uuid : '',
            'bulk_item_id'  => $is_bulk_context ? $bulk_item_id : 0,
        ];
        $metadata = array_merge( $metadata, $coordinator->item_identity_metadata( $context ) );
        if ( empty( $product_images ) || ! is_array( $product_images ) ) {
            return Messages::error( 'request_failed', 500, [], [ 'errorCode' => 'INVALID_PAYLOAD' ] );
        }
		if ( count( $product_images ) > 10 ) {
            return new \WP_Error(
                'fotogenic_ai_too_many_images',
				__( 'Select up to 10 product images for generation.', 'fotogenic-ai' ),
                [ 'status' => 400 ]
            );
        }

        $source_attachment_ids = array_values(
            array_unique(
                array_filter(
                    array_map(
                        static fn( array $image ): int => absint( $image['attachment_id'] ?? 0 ),
                        $product_images
                    )
                )
            )
        );
        $metadata['source_attachment_id'] = (int) ( $source_attachment_ids[0] ?? 0 );
        $metadata['source_attachment_ids'] = $source_attachment_ids;
        $metadata['expected_output_count'] = $images_count;
        $metadata['images_count'] = $images_count;
		$pricing = [] !== $trusted_pricing
			? Workflow_Preflight::normalize_trusted_pricing( $trusted_pricing, self::WORKFLOW, $images_count, $quality )
			: Price_Service::instance()->get_generate_images_pricing( $quality );
		if ( is_wp_error( $pricing ) ) {
			return $pricing;
		}
		$price_per_image = [] !== $trusted_pricing
			? (float) $pricing['creditsPerOutput']
			: (float) $pricing['credits_per_image'];
        $metadata['estimated_cost'] = $price_per_image * $images_count;
        $metadata['quality'] = $quality;

        $admission = $coordinator->admit_request(
            $user_id,
            self::WORKFLOW,
            $request_id,
            $fingerprint,
            $context,
            $metadata,
            $universal_fingerprint
        );
        if ( is_wp_error( $admission ) ) {
            return $admission;
        }
        if ( ! empty( $admission['replayed'] ) ) {
            return $this->format_start_result( $admission['result'] ?? Messages::error( 'request_failed', 500 ) );
        }
		$idempotency_key = $coordinator->get_upstream_idempotency_key( $admission );
		if ( is_wp_error( $idempotency_key ) ) {
			return $idempotency_key;
		}
        $start = $coordinator->begin_start(
            $user_id,
            self::WORKFLOW,
            $request_id,
            $context,
            $metadata,
            $admission
        );
        if ( is_wp_error( $start ) ) {
            return $start;
        }

        $run_id = (string) ( $start['run_id'] ?? '' );
        $logger = Logger::instance();
        $start_resolved = false;
        try {
            $should_fetch_config = $auto_configure;
            $config_fetch_skipped = ! $should_fetch_config;
            $config_fetch_skip_reason = '';
			$config_source = 'not_requested';
            $allowed_keys_source = 'schema';
            $auto_config_ran_in_this_run = false;
            $config = null;
            $config_selections = [];

            if ( $should_fetch_config ) {
                $provider_result = Config_Provider::get_config();
                $config = $provider_result['data'] ?? null;
                $config_source = isset( $provider_result['source'] ) ? (string) $provider_result['source'] : 'network';
                $config_service = new Service_Configuration();
                if ( ! is_array( $config ) || ! $config_service->is_configuration_complete( $config ) ) {
					$config_error = Messages::error(
						'request_failed',
						500,
						[],
						[
							'errorCode'     => 'CONFIG_REQUEST_FAILED',
							'uncertain'     => false,
							'not_dispatched' => true,
						]
					);
                    $start_resolved = true;
                    return $coordinator->handle_upstream_error( $config_error, self::WORKFLOW, $request_id, $context, $start );
                }
                $config_selections = ( is_array( $config ) ? ( $config['selections'] ?? [] ) : [] );
                if ( ! is_array( $config_selections ) ) {
                    $config_selections = [];
                }
                if ( $auto_configure && ! empty( $config_selections ) ) {
                    $config_fields = [
                        'personPresence'      => is_array( $subject_image ) ? 'true' : 'false',
                        'hasEnvironmentImage' => is_array( $environment_image ) ? 'true' : 'false',
                    ];
                    $config_files = [
                        'productImages' => $product_images,
                    ];
                    if ( is_array( $subject_image ) ) {
                        $config_files['subjectImage'] = $subject_image;
                    }
                    if ( is_array( $environment_image ) ) {
                        $config_files['environmentImage'] = $environment_image;
                    }
                    if ( is_array( $inspiration_image ) ) {
                        $config_files['inspirationImage'] = $inspiration_image;
                    }
                    $config_result = Api_Client::instance()->request_multipart(
                        'configuration_generator',
                        $config_fields,
                        $config_files
                    );
                    if ( is_wp_error( $config_result ) ) {
						$config_error = Messages::error(
							'request_failed',
							500,
							[],
							[
								'errorCode'     => 'CONFIG_REQUEST_FAILED',
								'uncertain'     => false,
								'not_dispatched' => true,
							]
						);
                        $start_resolved = true;
                        return $coordinator->handle_upstream_error( $config_error, self::WORKFLOW, $request_id, $context, $start );
                    }
                    $config_selections = $config_result['selections'] ?? [];
                    if ( ! is_array( $config_selections ) ) {
                        $config_selections = [];
                    }
                    $auto_config_ran_in_this_run = true;
                }
                $allowed_keys_source = 'config';
            } else {
                $config_fetch_skip_reason = 'not_needed_schema';
            }

            $config_service = new Service_Configuration();
            if ( $config !== null ) {
                $allowed_selection_keys = $config_service->get_supported_selection_keys( $config );
            } else {
                $allowed_selection_keys = Selection_Schema::get_selection_keys();
            }
            $schema_keys = Selection_Schema::get_selection_keys();
			$selection_input = $command['selections'] ?? [];
            $selection_overrides = [];
            $selection_override_keys = [];
            $selections = [];
            $selection_keys_invalid_dropped = [];
            $aspect_ratio_auto = false;
            $aspect_ratio_explicit = false;
            $aspect_ratio_has_value = false;
            if ( is_array( $selection_input ) && ! empty( $selection_input ) ) {
                foreach ( $selection_input as $key => $value ) {
                    if ( ! Selection_Schema::is_valid_key( $key ) ) {
                        $selection_keys_invalid_dropped[ $key ] = true;
                        continue;
                    }
                    if ( ! in_array( $key, $allowed_selection_keys, true ) ) {
                        continue;
                    }
                    if ( ! is_array( $value ) ) {
                        $value = [ 'id' => $value ];
                    }
                    $selection_id = isset( $value['id'] ) ? sanitize_text_field( (string) $value['id'] ) : '';
                    if ( '' === $selection_id ) {
                        continue;
                    }
                    $selection_overrides[ $key ] = [
                        'id' => $selection_id,
                    ];
                    if ( 'aspectRatio' === $key && 'auto' === $selection_id ) {
                        $aspect_ratio_has_value = true;
                        $aspect_ratio_auto = true;
                    } elseif ( 'aspectRatio' === $key ) {
                        $aspect_ratio_has_value = true;
                        $aspect_ratio_explicit = true;
                    }
                }
                $selections = $selection_overrides;
            }
            // When client sends no selections, do not fill from config (no full default preset).

            if ( null !== $person_presence ) {
                $selections['personPresence'] = [
                    'id' => $person_presence ? 'yes' : 'no',
                ];
            }

            if ( ! empty( $selection_keys_invalid_dropped ) && $logger->enabled() && '' !== $run_id ) {
                $logger->info( 'selection_keys_invalid_dropped', [
                    'run_id'   => $run_id,
                    'dropped'  => array_keys( $selection_keys_invalid_dropped ),
                ] );
            }
            if ( ! empty( $selection_overrides ) ) {
                $selection_override_keys = array_values(
                    array_unique( array_merge( $selection_override_keys, array_keys( $selection_overrides ) ) )
                );
            }
            if ( ! $aspect_ratio_explicit && ! $aspect_ratio_has_value ) {
                $aspect_ratio_auto = true;
            }

            $keys_before_fill = array_keys( $selections );
            $selections = Selection_Schema::fill_required_from_defaults( $selections );
            $filled_default_keys = array_values( array_diff( array_keys( $selections ), $keys_before_fill ) );
            $explicit_keys = array_values( array_unique( array_merge(
                array_keys( $selection_overrides ),
                is_array( $selection_input ) ? array_keys( $selection_input ) : []
            ) ) );

            $merged_instructions = '';
            $global_instructions = '';
            if ( $apply_global_instructions ) {
                $global_instructions = trim( (string) ( $options['custom_instructions'] ?? '' ) );
            }
            $merged_instructions = trim( implode( "\n", array_filter( [ $custom_instructions, $global_instructions ] ) ) );

            $payload_subject_image = is_array( $subject_image ) ? $subject_image : null;
            $multipart = ( new Generate_Images_Multipart_Builder() )->build(
                [
                    'quality'             => $quality,
                    'count'               => $images_count,
                    'selections'          => $selections,
					'custom_instructions' => $merged_instructions,
					'style'               => $style,
                    'include_face'        => $include_face,
                    'include_body'        => $include_body,
                    'look_at_camera'      => $look_at_camera,
                    'product_images'      => is_array( $product_images ) ? $product_images : [],
                    'subject_image'       => $payload_subject_image,
                    'environment_image'   => is_array( $environment_image ) ? $environment_image : null,
                    'inspiration_image'   => is_array( $inspiration_image ) ? $inspiration_image : null,
                ]
            );
            if ( is_wp_error( $multipart ) ) {
                $start_resolved = true;
                return $coordinator->handle_upstream_error( $multipart, self::WORKFLOW, $request_id, $context, $start );
            }
            $fields = $multipart['fields'];
            $files = $multipart['files'];
            if ( null === $payload_subject_image && ( null !== $include_face || null !== $include_body || null !== $look_at_camera ) ) {
                if ( $logger->enabled() && '' !== $run_id ) {
                    $logger->info( 'model_flags_dropped', [
                        'run_id'   => $run_id,
                        'reason'   => 'subjectImage_not_in_payload',
                        'includeFace' => $include_face,
                        'includeBody' => $include_body,
                        'lookAtCamera' => $look_at_camera,
                    ] );
                }
            }

            $primary_images_count = is_array( $product_images ) ? count( $product_images ) : 0;
            $subject_included_payload = null !== $payload_subject_image;
            $environment_included_payload = is_array( $environment_image );
            $inspiration_included_payload = is_array( $inspiration_image );
            $images_count_input_payload = $primary_images_count
                + ( $subject_included_payload ? 1 : 0 )
                + ( $environment_included_payload ? 1 : 0 )
                + ( $inspiration_included_payload ? 1 : 0 );
            $payload_images_roles = [
                'subject_included'     => $subject_included_payload,
                'environment_included' => $environment_included_payload,
                'inspiration_included' => $inspiration_included_payload,
                'primary_count'        => $primary_images_count,
            ];
            $image_builder_log = new Generate_Image_Builder();
            $image_builder_log->log_counts_for_request(
                'generate_start',
                $run_target,
                $images_count_input_payload,
                $subject_included_payload,
                $environment_included_payload,
                $primary_images_count,
                $primary_images_count > 0,
                $inspiration_included_payload
            );

            if ( '' !== $run_id ) {
                $logger->update_run( $run_id, [
					'images_count' => $images_count,
					'quality'      => $quality,
                ] );
            }

            if ( $logger->enabled() && '' !== $run_id ) {
                $payload_keys_sent = array_keys( $selections );
                $selections_count = count( $selections );
                $payload_summary = [
                    'quality'                  => $quality,
                    'count'                    => $images_count,
                    'selections_count'         => $selections_count,
                    'has_custom_instructions'  => '' !== $merged_instructions,
                    'subject_included'        => $subject_included_payload,
                    'environment_included'     => $environment_included_payload,
                    'inspiration_included'    => $inspiration_included_payload,
                ];
                $log_context = [
                    'run_id'                    => $run_id,
                    'run_target'                => $run_target,
                    'subject_id'                => $subject_id,
                    'payload_summary'          => $payload_summary,
                    'payload_images_roles'     => $payload_images_roles,
                    'config_fetch_skipped'      => $config_fetch_skipped,
                    'config_fetch_skip_reason'  => $config_fetch_skip_reason,
                    'config_source'             => $config_source,
                    'allowed_keys_source'       => $allowed_keys_source,
                    'allowed_keys_count'       => count( $allowed_selection_keys ),
                    'filled_default_keys'       => $filled_default_keys,
                    'filled_default_keys_count' => count( $filled_default_keys ),
                    'explicit_keys_count'      => count( $explicit_keys ),
                    'payload_keys_sent'        => $payload_keys_sent,
                    'auto_config_requested'    => $auto_config_ran_in_this_run,
                    'images_count_input'       => $images_count_input_payload,
                    'primary_images_count'     => $primary_images_count,
                    'images_count'              => $images_count,
                ];
                $logger->info( 'generate_payload', $log_context );
            }

			$prepared_start = $coordinator->prepare_upstream_dispatch( $start );
			if ( is_wp_error( $prepared_start ) ) {
				$start_resolved = true;
				return $coordinator->handle_upstream_error( $prepared_start, self::WORKFLOW, $request_id, $context, $start );
			}
			$start = $prepared_start;

			$images_response = Api_Client::instance()->request_multipart(
                'images_generator',
                $fields,
                $files,
                [
					'request_id'      => $request_id,
					'run_id'          => $run_id,
					'idempotency_key' => $idempotency_key,
                ]
            );
            if ( is_wp_error( $images_response ) ) {
                if ( 'fotogenic_ai_request_failed' === $images_response->get_error_code() ) {
                    $error_data = $images_response->get_error_data();
                    $error_data = is_array( $error_data ) ? $error_data : [];
                    if ( empty( $error_data['uncertain'] ) ) {
                        $images_response = Messages::error( 'request_failed', 500, [], [ 'errorCode' => 'START_REQUEST_FAILED' ] );
                    }
                }
                $start_resolved = true;
                return $coordinator->handle_upstream_error( $images_response, self::WORKFLOW, $request_id, $context, $start );
            }

            $metadata['quality'] = $quality;
            $metadata['scene_description'] = '' !== $auto_config_description
                ? $auto_config_description
                : (string) ( $config_result['description'] ?? $merged_instructions );
            $metadata['selections'] = $selections;
			$captured = $coordinator->capture_upstream_start_response( self::WORKFLOW, $start, $images_response );
			if ( is_wp_error( $captured ) ) {
				$start_resolved = true;
				return $coordinator->handle_upstream_error( $captured, self::WORKFLOW, $request_id, $context, $start );
			}
			$start['request_record'] = $captured['request_record'];
			$job_ids = $captured['job_ids'];
			$start_resolved = true;
            $result = $coordinator->complete_start(
                $user_id,
                self::WORKFLOW,
                $request_id,
                $context,
                $start,
                $job_ids,
                $metadata
            );
            return $this->format_start_result( $result );
        } finally {
            if ( ! $start_resolved ) {
                $coordinator->handle_upstream_error(
                    new \WP_Error(
                        'fotogenic_ai_generation_start_uncertain',
                        __( 'The start response could not be confirmed. Do not retry yet; refresh this generation shortly.', 'fotogenic-ai' ),
                        [ 'status' => 503, 'uncertain' => true ]
                    ),
                    self::WORKFLOW,
                    $request_id,
                    $context,
                    $start
                );
            }
        }
    }

    /** @return array|string|\WP_Error */
    private function resolve_optional_image_file( int $attachment_id ) {
        if ( $attachment_id <= 0 ) {
            return '';
        }

        return Image_Source_Resolver::instance()->get_image_file_for_attachment( $attachment_id );
    }

    /**
     * @param mixed $result Operation result.
     * @return array|\WP_Error
     */
    private function format_start_result( $result ) {
        if ( is_wp_error( $result ) ) {
            return $result;
        }
        if ( ! is_array( $result ) ) {
            return Messages::error( 'request_failed', 500 );
        }

		return $result;
    }
}
