<?php

namespace Fotogenic_AI;

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

final class Service_Generate_Configuration {
	private const UNIVERSAL_REQUEST_FIELDS = [
		'schemaVersion',
		'workflow',
		'sourceType',
		'scope',
		'subjectId',
		'sourceAttachmentIds',
		'references',
	];

	private const REFERENCE_FIELDS = [ 'subjectImageId', 'inspirationImageId', 'environmentImageId' ];

	/**
	 * Run the non-billable helper from strict WordPress IDs only.
	 *
	 * @param mixed $raw_request Raw request payload.
	 * @return array|\WP_Error
	 */
	public function generate_universal_configuration( $raw_request ) {
		$request = $this->normalize_universal_request( $raw_request );
		if ( is_wp_error( $request ) ) {
			return $request;
		}

		$config_result = Config_Provider::get_config();
		$configuration = isset( $config_result['data'] ) && is_array( $config_result['data'] )
			? $config_result['data']
			: [];
		if ( ! ( new Service_Configuration() )->is_configuration_complete( $configuration ) ) {
			return $this->universal_error(
				'fotogenic_ai_configuration_unavailable',
				__( 'Configuration options are temporarily unavailable. Retry when the options have loaded.', 'fotogenic-ai' ),
				503
			);
		}

		$primary_files = Image_Source_Resolver::instance()->get_image_files_for_attachments( $request['sourceAttachmentIds'] );
		if ( is_wp_error( $primary_files ) ) {
			return $primary_files;
		}
		$references = [];
		foreach ( self::REFERENCE_FIELDS as $field ) {
			$attachment_id = (int) ( $request['references'][ $field ] ?? 0 );
			if ( $attachment_id <= 0 ) {
				continue;
			}
			$file = Image_Source_Resolver::instance()->get_image_file_for_attachment( $attachment_id );
			if ( is_wp_error( $file ) ) {
				return $file;
			}
			$references[ $field ] = $file;
		}

		$person_presence = isset( $references['subjectImageId'] );
		$has_environment = isset( $references['environmentImageId'] );
		$fields          = [
			'personPresence'      => $person_presence,
			'hasEnvironmentImage' => $has_environment,
		];
		$files           = [ 'productImages' => $primary_files ];
		$file_roles      = [
			'subjectImageId'     => 'subjectImage',
			'inspirationImageId' => 'inspirationImage',
			'environmentImageId' => 'environmentImage',
		];
		foreach ( $file_roles as $reference_field => $file_role ) {
			if ( isset( $references[ $reference_field ] ) ) {
				$files[ $file_role ] = $references[ $reference_field ];
			}
		}

		$api_response = Api_Client::instance()->request_multipart( 'configuration_generator', $fields, $files );
		if ( is_wp_error( $api_response ) ) {
			$status = (int) ( $api_response->get_error_data()['status'] ?? 500 );
			return $this->universal_error(
				'fotogenic_ai_configuration_failed',
				__( 'Configuration could not be generated. Review the selected images and retry.', 'fotogenic-ai' ),
				$status >= 400 && $status <= 599 ? $status : 500
			);
		}

		$recipe_patch = $this->build_universal_recipe_patch(
			is_array( $api_response ) ? $api_response : [],
			$configuration,
			$person_presence,
			$has_environment
		);

		return [
			'recipePatch' => $recipe_patch,
			'derived'     => [
				'personPresence'      => $person_presence,
				'hasEnvironmentImage' => $has_environment,
			],
		];
	}

	/**
	 * @param mixed $raw_request Raw request payload.
	 * @return array|\WP_Error
	 */
	private function normalize_universal_request( $raw_request ) {
		$allowed = Workflow_Contract_Guard::reject_forbidden( $raw_request );
		if ( is_wp_error( $allowed ) ) {
			return $allowed;
		}
		if ( ! ( $raw_request instanceof \stdClass ) ) {
			return $this->universal_invalid();
		}
		$request = get_object_vars( $raw_request );
		if (
			count( $request ) !== count( self::UNIVERSAL_REQUEST_FIELDS )
			|| ! empty( array_diff( array_keys( $request ), self::UNIVERSAL_REQUEST_FIELDS ) )
			|| ! empty( array_diff( self::UNIVERSAL_REQUEST_FIELDS, array_keys( $request ) ) )
		) {
			return $this->universal_invalid();
		}
		if (
			! is_int( $request['schemaVersion'] )
			|| Workflow_Registry::SCHEMA_VERSION !== $request['schemaVersion']
			|| 'product_images' !== $request['workflow']
			|| ! is_string( $request['sourceType'] )
			|| 'single' !== $request['scope']
			|| ! is_int( $request['subjectId'] )
			|| $request['subjectId'] <= 0
			|| ! is_array( $request['sourceAttachmentIds'] )
			|| ! fotogenic_ai_array_is_list( $request['sourceAttachmentIds'] )
			|| ! ( $request['references'] instanceof \stdClass )
		) {
			return $this->universal_invalid();
		}

		$source_attachment_ids = [];
		foreach ( $request['sourceAttachmentIds'] as $attachment_id ) {
			if ( ! is_int( $attachment_id ) || $attachment_id <= 0 || in_array( $attachment_id, $source_attachment_ids, true ) ) {
				return $this->universal_invalid();
			}
			$source_attachment_ids[] = $attachment_id;
		}
		if ( empty( $source_attachment_ids ) || count( $source_attachment_ids ) > 10 ) {
			return $this->universal_invalid();
		}

		$reference_members = get_object_vars( $request['references'] );
		if ( ! empty( array_diff( array_keys( $reference_members ), self::REFERENCE_FIELDS ) ) ) {
			return $this->universal_invalid();
		}
		$references = [];
		foreach ( $reference_members as $field => $attachment_id ) {
			if ( ! is_int( $attachment_id ) || $attachment_id <= 0 ) {
				return $this->universal_invalid();
			}
			$references[ $field ] = $attachment_id;
		}

		$draft = json_decode(
			(string) wp_json_encode(
				[
					'schemaVersion' => Workflow_Registry::SCHEMA_VERSION,
					'workflow'      => 'product_images',
					'sourceType'    => $request['sourceType'],
					'scope'         => 'single',
					'selection'     => [
						'strategy'    => 'explicit',
						'selectedIds' => [ $request['subjectId'] ],
						'excludedIds' => [],
						'query'       => new \stdClass(),
					],
					'sourcePolicy'  => [ 'attachmentIds' => $source_attachment_ids ],
					'recipe'        => array_merge( [ 'count' => 1 ], $references ),
					'resultPolicy'  => 'product' === $request['sourceType']
						? (object) [ 'assignmentMode' => 'review' ]
						: new \stdClass(),
				]
			),
			false
		);
		$normalized = ( new Workflow_Draft_Normalizer() )->normalize( $draft );
		if ( is_wp_error( $normalized ) ) {
			return $normalized;
		}
		$snapshot = ( new Workflow_Source_Preflight() )->build_explicit_snapshot( $normalized );
		if ( is_wp_error( $snapshot ) ) {
			return $snapshot;
		}
		if ( 1 !== count( $snapshot ) || empty( $snapshot[0]['attachmentIds'] ) ) {
			return $this->universal_invalid();
		}

		return [
			'sourceAttachmentIds' => $snapshot[0]['attachmentIds'],
			'references'           => $references,
		];
	}

	private function build_universal_recipe_patch(
		array $api_response,
		array $configuration,
		bool $person_presence,
		bool $has_environment
	): array {
		$source = isset( $api_response['result'] ) && is_array( $api_response['result'] )
			? $api_response['result']
			: $api_response;
		$available = ( new Service_Configuration() )->get_selection_ids( $configuration );
		$selections = [];
		foreach ( $available as $key => $ids ) {
			if ( ! array_key_exists( $key, $source ) ) {
				continue;
			}
			$raw = $source[ $key ];
			$id  = is_array( $raw ) ? ( $raw['id'] ?? $raw['value'] ?? '' ) : $raw;
			$id  = sanitize_text_field( (string) $id );
			if ( '' === $id || ( 'aspectRatio' === $key && 'auto' === strtolower( $id ) ) || ! in_array( $id, $ids, true ) ) {
				continue;
			}
			$selections[ $key ] = [ 'id' => $id ];
		}
		if ( ! $has_environment ) {
			unset( $selections['setting'], $selections['bgElements'] );
		}

		$patch = [
			'autoConfigUsed' => true,
			'personPresence' => $person_presence,
		];
		if ( ! empty( $selections ) ) {
			$patch['selections'] = $selections;
		}
		$custom_instructions = sanitize_textarea_field( (string) ( $source['customInstructions'] ?? '' ) );
		if ( '' !== $custom_instructions ) {
			$patch['customInstructions'] = $custom_instructions;
		}
		$description = sanitize_textarea_field( (string) ( $source['description'] ?? '' ) );
		if ( '' !== $description ) {
			$patch['autoConfigDescription'] = $description;
		}
		if ( $person_presence ) {
			foreach ( [ 'includeFace', 'includeBody', 'lookAtCamera' ] as $field ) {
				if ( isset( $source[ $field ] ) && '' !== $source[ $field ] ) {
					$patch[ $field ] = (bool) rest_sanitize_boolean( $source[ $field ] );
				}
			}
		}

		return $patch;
	}

	private function universal_invalid(): \WP_Error {
		return $this->universal_error(
			'fotogenic_ai_invalid_configuration_request',
			__( 'The configuration request is invalid.', 'fotogenic-ai' ),
			400
		);
	}

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