<?php

namespace Fotogenic_AI;

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

/**
 * REST boundary for the universal manifest and non-billable Studio tools.
 */
final class Rest_Universal_Studio {
	private Workflow_Preflight $preflight;
	private Universal_Start_Service $start_service;
	private ?Service_Generate_Configuration $configuration_service;
	private ?Service_Presets $presets_service;

	public function __construct(
		?Workflow_Preflight $preflight = null,
		?Universal_Start_Service $start_service = null,
		?Service_Generate_Configuration $configuration_service = null,
		?Service_Presets $presets_service = null
	) {
		$this->preflight             = $preflight ?? new Workflow_Preflight();
		$this->start_service         = $start_service ?? new Universal_Start_Service();
		$this->configuration_service = $configuration_service;
		$this->presets_service       = $presets_service;
	}

	public function register_routes( Rest_Router $router ): void {
		$router->register_route(
			'fotogenic-ai/v1',
			'/studio/estimate-context',
			[
				'methods'             => 'POST',
				'callback'            => [ $this, 'handle_estimate_context' ],
				'permission_callback' => [ $router, 'permissions_generate' ],
				'args'                => [
					'tier'    => [
						'type'    => 'string',
						'default' => '',
						'enum'    => [ '', 'imageGenerationHighQuality', 'imageGenerationUltraHighQuality', 'campaignSetGenerationCreditsPerImage', 'highQualityEnhanceGeneration' ],
					],
					'balance' => [ 'type' => 'boolean', 'default' => false ],
				],
			]
		);
		$router->register_route(
			'fotogenic-ai/v1',
			'/studio/manifest',
			[
				'methods'             => 'GET',
				'callback'            => [ $this, 'handle_manifest' ],
				'permission_callback' => [ $router, 'permissions_generate' ],
			]
		);
		$router->register_route(
			'fotogenic-ai/v1',
			'/studio/preflight',
			[
				'methods'             => 'POST',
				'callback'            => [ $this, 'handle_preflight' ],
				'permission_callback' => [ $router, 'permissions_generate_upload' ],
			]
		);
		$router->register_route(
			'fotogenic-ai/v1',
			'/studio/start',
			[
				'methods'             => 'POST',
				'callback'            => [ $this, 'handle_start' ],
				'permission_callback' => [ $router, 'permissions_generate_upload' ],
			]
		);
		$router->register_route(
			'fotogenic-ai/v1',
			'/studio/generate-configuration',
			[
				'methods'             => 'POST',
				'callback'            => [ $this, 'handle_generate_configuration' ],
				'permission_callback' => [ $router, 'permissions_generate_upload' ],
			]
		);
		$router->register_route(
			'fotogenic-ai/v1',
			'/studio/presets',
			[
				'methods'             => 'GET',
				'callback'            => [ $this, 'handle_presets_list' ],
				'permission_callback' => [ $router, 'permissions_admin' ],
			]
		);
		$router->register_route(
			'fotogenic-ai/v1',
			'/studio/presets/get',
			[
				'methods'             => 'GET',
				'callback'            => [ $this, 'handle_preset_get' ],
				'permission_callback' => [ $router, 'permissions_admin' ],
			]
		);
		$router->register_route(
			'fotogenic-ai/v1',
			'/studio/presets/save',
			[
				'methods'             => 'POST',
				'callback'            => [ $this, 'handle_preset_save' ],
				'permission_callback' => [ $router, 'permissions_admin' ],
			]
		);
		$router->register_route(
			'fotogenic-ai/v1',
			'/studio/presets/delete',
			[
				'methods'             => 'POST',
				'callback'            => [ $this, 'handle_preset_delete' ],
				'permission_callback' => [ $router, 'permissions_admin' ],
			]
		);
	}

	public function handle_manifest( \WP_REST_Request $request ): \WP_REST_Response {
		unset( $request );

		return $this->no_store( Workflow_Registry::get_browser_projection() );
	}

	/** Display data only: reuse account caches without preparing a billable run. */
	public function handle_estimate_context( \WP_REST_Request $request ): \WP_REST_Response {
		$result = [];
		$tier   = (string) $request->get_param( 'tier' );
		if ( '' !== $tier ) {
			$pricing = Price_Service::instance()->get_status();
			if ( ! isset( $pricing['tiers'][ $tier ] ) ) {
				$pricing = Price_Service::instance()->refresh();
			}
			$result['pricing'] = $pricing;
		}
		if ( $request->get_param( 'balance' ) ) {
			$credits = Credits_Service::instance()->get_status( 0 );
			if ( is_wp_error( $credits ) ) {
				$credits = Credits_Service::instance()->refresh( 0 );
			}
			$result['credits'] = is_wp_error( $credits ) ? null : $credits;
		}

		return $this->no_store( $result );
	}

	/**
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function handle_preflight( \WP_REST_Request $request ) {
		$draft = $this->decode_json_object( $request );
		if ( is_wp_error( $draft ) ) {
			return $draft;
		}

		$result = $this->preflight->evaluate( $draft );
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		return $this->no_store( $result );
	}

	/**
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function handle_start( \WP_REST_Request $request ) {
		$not_ready = $this->migration_error();
		if ( is_wp_error( $not_ready ) ) {
			return $not_ready;
		}
		$envelope = $this->decode_json_root( $request );
		if ( is_wp_error( $envelope ) ) {
			return $envelope;
		}

		$result = $this->start_service->start( $envelope );
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		return $this->no_store( $result );
	}

	/**
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function handle_generate_configuration( \WP_REST_Request $request ) {
		$decoded = $this->decode_json_root( $request );
		if ( is_wp_error( $decoded ) ) {
			return $decoded;
		}
		$members = get_object_vars( $decoded );
		if ( [ 'request' ] !== array_keys( $members ) || ! ( $members['request'] instanceof \stdClass ) ) {
			return $this->invalid_json_shape();
		}
		$service = $this->configuration_service ?? new Service_Generate_Configuration();
		$result  = $service->generate_universal_configuration( $members['request'] );
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		return $this->no_store( $result );
	}

	/**
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function handle_presets_list( \WP_REST_Request $request ) {
		$not_ready = $this->migration_error();
		if ( is_wp_error( $not_ready ) ) {
			return $not_ready;
		}
		$params = $this->read_string_params( $request, [ 'workflow', 'sourceType', 'scope' ] );
		if ( is_wp_error( $params ) ) {
			return $params;
		}
		$service = $this->presets_service ?? new Service_Presets();
		$result  = $service->list_universal_presets(
			$params['workflow'],
			$params['sourceType'],
			$params['scope']
		);
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		return $this->no_store( $result );
	}

	/**
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function handle_preset_get( \WP_REST_Request $request ) {
		$not_ready = $this->migration_error();
		if ( is_wp_error( $not_ready ) ) {
			return $not_ready;
		}
		$params = $this->read_string_params( $request, [ 'uuid', 'workflow', 'sourceType', 'scope' ] );
		if ( is_wp_error( $params ) ) {
			return $params;
		}
		$service = $this->presets_service ?? new Service_Presets();
		$result  = $service->get_universal_preset(
			$params['uuid'],
			$params['workflow'],
			$params['sourceType'],
			$params['scope']
		);
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		return $this->no_store( $result );
	}

	/**
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function handle_preset_save( \WP_REST_Request $request ) {
		$not_ready = $this->migration_error();
		if ( is_wp_error( $not_ready ) ) {
			return $not_ready;
		}
		$decoded = $this->decode_json_root( $request );
		if ( is_wp_error( $decoded ) ) {
			return $decoded;
		}
		$service = $this->presets_service ?? new Service_Presets();
		$result  = $service->save_universal_preset( $decoded );
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		return $this->no_store( $result );
	}

	/**
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function handle_preset_delete( \WP_REST_Request $request ) {
		$not_ready = $this->migration_error();
		if ( is_wp_error( $not_ready ) ) {
			return $not_ready;
		}
		$decoded = $this->decode_json_root( $request );
		if ( is_wp_error( $decoded ) ) {
			return $decoded;
		}
		$service = $this->presets_service ?? new Service_Presets();
		$result  = $service->delete_universal_preset( $decoded );
		if ( is_wp_error( $result ) ) {
			return $result;
		}

		return $this->no_store( $result );
	}

	/**
	 * Keep JSON objects distinct from arrays until strict type validation.
	 *
	 * @return \stdClass|\WP_Error
	 */
	private function decode_json_object( \WP_REST_Request $request ) {
		$decoded = $this->decode_json_root( $request );
		if ( is_wp_error( $decoded ) ) {
			return $decoded;
		}

		$members = get_object_vars( $decoded );
		if ( [ 'draft' ] !== array_keys( $members ) ) {
			return new \WP_Error(
				'fotogenic_ai_unexpected_preflight_field',
				__( 'The Studio preflight body must contain only the draft object.', 'fotogenic-ai' ),
				[ 'status' => 400 ]
			);
		}
		if ( ! ( $members['draft'] instanceof \stdClass ) ) {
			return new \WP_Error(
				'fotogenic_ai_invalid_draft_type',
				__( 'The Studio draft must be a JSON object.', 'fotogenic-ai' ),
				[ 'status' => 400 ]
			);
		}

		return $members['draft'];
	}

	/**
	 * Decode exactly one JSON root object without REST parameter coercion.
	 *
	 * @return \stdClass|\WP_Error
	 */
	private function decode_json_root( \WP_REST_Request $request ) {
		$content_type = $request->get_content_type();
		if ( ! is_array( $content_type ) || 'application/json' !== (string) ( $content_type['value'] ?? '' ) ) {
			return new \WP_Error(
				'fotogenic_ai_studio_json_required',
				__( 'Studio requests must use application/json.', 'fotogenic-ai' ),
				[ 'status' => 415 ]
			);
		}

		$body = $request->get_body();
		if ( ! is_string( $body ) || '' === trim( $body ) ) {
			return $this->invalid_json();
		}
		try {
			$decoded = json_decode( $body, false, 64, JSON_THROW_ON_ERROR );
		} catch ( \JsonException $exception ) {
			unset( $exception );
			return $this->invalid_json();
		}
		if ( ! ( $decoded instanceof \stdClass ) ) {
			return new \WP_Error(
				'fotogenic_ai_invalid_draft_type',
				__( 'The Studio request body must be a JSON object.', 'fotogenic-ai' ),
				[ 'status' => 400 ]
			);
		}
		return $decoded;
	}

	private function no_store( array $data ): \WP_REST_Response {
		$response = rest_ensure_response( $data );
		$response->header( 'Cache-Control', 'no-store' );
		return $response;
	}

	private function migration_error(): ?\WP_Error {
		$migration = Universal_Data_Migration::instance();
		return $migration->is_ready() ? null : $migration->readiness_error();
	}

	private function invalid_json(): \WP_Error {
		return new \WP_Error(
			'fotogenic_ai_invalid_studio_json',
			__( 'The Studio request JSON is invalid.', 'fotogenic-ai' ),
			[ 'status' => 400 ]
		);
	}

	private function invalid_json_shape(): \WP_Error {
		return new \WP_Error(
			'fotogenic_ai_invalid_studio_request',
			__( 'The Studio request contains unsupported fields.', 'fotogenic-ai' ),
			[ 'status' => 400 ]
		);
	}

	/**
	 * @param string[] $names Required scalar query parameter names.
	 * @return array<string,string>|\WP_Error
	 */
	private function read_string_params( \WP_REST_Request $request, array $names ) {
		$params = [];
		foreach ( $names as $name ) {
			$value = $request->get_param( $name );
			if ( ! is_string( $value ) || '' === $value ) {
				return $this->invalid_json_shape();
			}
			$params[ $name ] = $value;
		}

		return $params;
	}
}
