<?php

/**
 * Builds WordPress Playground blueprint URLs for built blocks.
 *
 * @package LolaCore\BlockBuilder\Playground
 * @license GPL-2.0-or-later
 */

declare(strict_types=1);

namespace LolaCore\BlockBuilder\Playground;

// phpcs:disable WordPress.Security.EscapeOutput.ExceptionNotEscaped -- Diagnostic exception messages; escaped at REST/chat presentation layer.

use LolaCore\BlockBuilder\Artifact\BlockArtifactAdapter;
use LolaCore\BlockBuilder\PostType\BlockPostType;
use LolaCore\Builder\Artifact\FilesMap;
use LolaCore\Builder\Playground\BlueprintBuilder;

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

/**
 * Converts block library entries into Playground blueprint URLs.
 */
class BlockBlueprintGenerator {

	public const PLAYGROUND_BASE_URL = BlueprintBuilder::PLAYGROUND_BASE_URL;

	public const PLAYGROUND_BLUEPRINT_URL_BASE = BlueprintBuilder::PLAYGROUND_BLUEPRINT_URL_BASE;

	private BlockArtifactAdapter $adapter;

	public function __construct( ?BlockArtifactAdapter $adapter = null ) {
		$this->adapter = $adapter ?? new BlockArtifactAdapter();
	}

	public function build( int $postId ): string {
		return $this->buildShareableUrl($postId);
	}

	public function buildShareableUrl( int $postId ): string {
		$this->loadBlockPayload($postId);

		$hostedUrl = $this->buildHostedBlueprintUrl($postId);

		return self::PLAYGROUND_BLUEPRINT_URL_BASE . rawurlencode($hostedUrl);
	}

	public function buildHostedBlueprintUrl( int $postId ): string {
		$this->loadBlockPayload($postId);
		$token = BlockPlaygroundAccessToken::forPost($postId);

		$hostedUrl = rest_url('lolacore/v1/block-builder/playground-blueprint/' . $postId);
		if (! is_string($hostedUrl) || $hostedUrl === '') {
			throw new \Exception(__('Could not build the hosted Playground blueprint URL.', 'lolacore'));
		}

		return add_query_arg(
			array('token' => $token),
			$hostedUrl
		);
	}

	/**
	 * Block blueprints: write files to lolacore-blocks/ + single Playground host plugin.
	 *
	 * @return array<string, mixed>
	 */
	public function buildBlueprint( array $payload ): array {
		$install_slug = sanitize_title((string) ( $payload['install_slug'] ?? $payload['block_slug'] ?? '' ));
		$files        = $payload['files_map'] ?? null;
		$title        = (string) ( $payload['name'] ?? $install_slug );

		if ($install_slug === '' || ! $files instanceof FilesMap) {
			throw new \Exception(__('Built block payload is incomplete.', 'lolacore'));
		}

		$steps = array(
			array(
				'step' => 'login',
			),
		);

		$sanitized_files = array();
		foreach ($files->all() as $relPath => $content) {
			if (! is_string($relPath) || ! is_string($content)) {
				continue;
			}
			$sanitized_files[ $relPath ] = BlueprintBuilder::sanitizeFileContent($content);
		}

		if ($sanitized_files === array()) {
			throw new \Exception(__('Built block file map is empty.', 'lolacore'));
		}

		$steps[] = array(
			'step'        => 'writeFiles',
			'writeToPath' => '/wordpress/wp-content/lolacore-blocks/' . $install_slug,
			'filesTree'   => array(
				'resource' => 'literal:directory',
				'name'     => $install_slug,
				'files'    => $sanitized_files,
			),
		);

		$host_files = array(
			BlockPlaygroundHost::mainFileRelPath() => BlockPlaygroundHost::buildHostPhp($install_slug, $title),
		);

		$steps[] = array(
			'step'       => 'installPlugin',
			'pluginData' => array(
				'resource' => 'literal:directory',
				'name'     => BlockPlaygroundHost::PLUGIN_SLUG,
				'files'    => $host_files,
			),
			'options'    => array(
				'activate' => false,
			),
		);

		$steps[] = array(
			'step'       => 'activatePlugin',
			'pluginPath' => BlockPlaygroundHost::PLUGIN_SLUG . '/' . BlockPlaygroundHost::mainFileRelPath(),
			'pluginName' => BlockPlaygroundHost::PLUGIN_SLUG,
		);

		return array(
			'$schema'           => BlueprintBuilder::SCHEMA_URL,
			'landingPage'       => '/wp-admin/post-new.php?post_type=page',
			'preferredVersions' => array(
				'php' => '8.3',
				'wp'  => 'latest',
			),
			'features'          => array(
				'networking' => true,
			),
			'steps'             => $steps,
		);
	}

	/**
	 * @return array{
	 *     post_id: int,
	 *     name: string,
	 *     block_name: string,
	 *     block_slug: string,
	 *     install_slug: string,
	 *     plugin_slug: string,
	 *     version: int,
	 *     files_map: \LolaCore\Builder\Artifact\FilesMap
	 * }
	 */
	public function loadBlockPayload( int $postId ): array {
		$post = get_post($postId);
		if (! $post instanceof \WP_Post || $post->post_type !== BlockPostType::POST_TYPE) {
			throw new \Exception(__('Built block not found.', 'lolacore'));
		}

		$block_slug   = (string) get_post_meta($postId, BlockPostType::META_BLOCK_SLUG, true);
		$install_slug = $this->adapter->slug($postId);
		if ($block_slug === '' || $install_slug === '') {
			throw new \Exception(__('Built block slug metadata is missing.', 'lolacore'));
		}

		return array(
			'post_id'      => $postId,
			'name'         => $post->post_title,
			'block_name'   => (string) get_post_meta($postId, BlockPostType::META_NAME, true),
			'block_slug'   => $block_slug,
			'install_slug' => $install_slug,
			'plugin_slug'  => $install_slug,
			'version'      => max(1, (int) get_post_meta($postId, BlockPostType::META_VERSION, true)),
			'files_map'    => $this->adapter->filesMap($postId),
		);
	}
}

