<?php
/**
 * Post Link Block module.
 *
 * Two server-rendered Gutenberg blocks:
 *  - `bw-dev/post-link-list`  (parent — layout selector + thumbnail width)
 *  - `bw-dev/post-link-item`  (child  — one internal post or external URL)
 *
 * Plus a REST endpoint `/bw-dev/v1/post-types` that lists public post types
 * for the inserter's "Post type" select.
 *
 * Ported from the standalone `bw-pretty-post-link` plugin. Block names, REST
 * namespace, and CSS classes were re-prefixed (see KNOWN-ISSUES.md). Pure
 * block module — no settings tab data; the tab renders inline docs only.
 *
 * @package BW_Dev
 */

defined( 'ABSPATH' ) || exit;

class BW_Dev_Module_Post_Link implements BW_Dev_Module_Interface {

	const REST_NAMESPACE = 'bw-dev/v1';

	public function slug(): string {
		return 'post_link';
	}

	public function label(): string {
		return __( 'Post Link Block', 'bw-dev' );
	}

	public function group(): string {
		return 'blocks';
	}

	public function default_settings(): array {
		return array();
	}

	public function sanitize( array $data ): array {
		// No persisted settings.
		unset( $data );
		return array();
	}

	public function register(): void {
		add_action( 'init',                       array( $this, 'register_blocks' ) );
		add_action( 'init',                       array( $this, 'register_frontend_style' ) );
		add_action( 'enqueue_block_editor_assets', array( $this, 'enqueue_editor_assets' ) );
		add_action( 'rest_api_init',              array( $this, 'register_rest_routes' ) );
	}

	public function register_blocks(): void {
		register_block_type(
			'bw-dev/post-link-item',
			array(
				'api_version'     => 3,
				'title'           => __( 'BW Post Link Item', 'bw-dev' ),
				'description'     => __( 'A single post link — internal (from any post type) or external.', 'bw-dev' ),
				'category'        => 'widgets',
				'icon'            => 'admin-links',
				'parent'          => array( 'bw-dev/post-link-list' ),
				'keywords'        => array( 'link', 'post', 'thumbnail' ),
				'supports'        => array(
					'html'                  => false,
					'reusable'              => false,
					'__experimentalToolbar' => false,
				),
				'attributes'      => array(
					'linkType'            => array( 'type' => 'string', 'default' => 'internal' ),
					'postType'            => array( 'type' => 'string', 'default' => 'post' ),
					'postId'              => array( 'type' => 'number', 'default' => 0 ),
					'customTitle'         => array( 'type' => 'string', 'default' => '' ),
					'customThumbnailId'   => array( 'type' => 'number', 'default' => 0 ),
					'externalTitle'       => array( 'type' => 'string', 'default' => '' ),
					'externalUrl'         => array( 'type' => 'string', 'default' => '' ),
					'externalThumbnailId' => array( 'type' => 'number', 'default' => 0 ),
				),
				'render_callback' => array( $this, 'render_item' ),
			)
		);

		register_block_type(
			'bw-dev/post-link-list',
			array(
				'api_version'     => 3,
				'title'           => __( 'BW Post Link List', 'bw-dev' ),
				'description'     => __( 'A list of nicely-rendered post links — internal or external — in Simple or Thumbnail layout.', 'bw-dev' ),
				'category'        => 'widgets',
				'icon'            => 'list-view',
				'keywords'        => array( 'link', 'list', 'post', 'thumbnail' ),
				'supports'        => array(
					'html'   => false,
					'align'  => array( 'wide', 'full' ),
					'anchor' => true,
				),
				'attributes'      => array(
					'layout'          => array( 'type' => 'string', 'default' => 'simple' ),
					'imgWidthPercent' => array( 'type' => 'number', 'default' => 20 ),
				),
				'render_callback' => array( $this, 'render_list' ),
			)
		);
	}

	public function register_frontend_style(): void {
		wp_register_style(
			'bw-dev-post-link-frontend',
			BW_DEV_URL . 'blocks/post-link/frontend.css',
			array(),
			BW_DEV_VERSION
		);
	}

	public function enqueue_editor_assets(): void {
		wp_enqueue_script(
			'bw-dev-post-link-editor',
			BW_DEV_URL . 'blocks/post-link/editor.js',
			array( 'wp-blocks', 'wp-element', 'wp-block-editor', 'wp-components', 'wp-data', 'wp-api-fetch', 'wp-i18n' ),
			BW_DEV_VERSION,
			true
		);
		wp_enqueue_style(
			'bw-dev-post-link-editor',
			BW_DEV_URL . 'blocks/post-link/editor.css',
			array(),
			BW_DEV_VERSION
		);
		// Frontend styles loaded in the editor too so blocks preview correctly.
		wp_enqueue_style( 'bw-dev-post-link-frontend' );
	}

	public function register_rest_routes(): void {
		register_rest_route(
			self::REST_NAMESPACE,
			'/post-types',
			array(
				'methods'             => 'GET',
				'callback'            => array( $this, 'rest_post_types' ),
				'permission_callback' => static function () {
					return current_user_can( 'edit_posts' );
				},
			)
		);
	}

	public function rest_post_types() {
		$excluded = array( 'attachment', 'wp_block', 'wp_template', 'wp_template_part', 'wp_navigation' );
		$types    = get_post_types( array( 'public' => true ), 'objects' );
		$out      = array();
		foreach ( $types as $slug => $obj ) {
			if ( in_array( $slug, $excluded, true ) ) {
				continue;
			}
			$out[] = array(
				'slug'      => $slug,
				'label'     => ! empty( $obj->labels->singular_name ) ? $obj->labels->singular_name : $obj->label,
				'rest_base' => ! empty( $obj->rest_base ) ? $obj->rest_base : $slug,
			);
		}
		return $out;
	}

	public function render_list( $attributes, $content ): string {
		wp_enqueue_style( 'bw-dev-post-link-frontend' );

		$layout    = ! empty( $attributes['layout'] ) ? $attributes['layout'] : 'simple';
		$img_width = isset( $attributes['imgWidthPercent'] ) ? (int) $attributes['imgWidthPercent'] : 20;
		$img_width = max( 10, min( 60, $img_width ) );

		if ( ! in_array( $layout, array( 'simple', 'thumbnail' ), true ) ) {
			$layout = 'simple';
		}

		$content = trim( (string) $content );

		$wrapper_attrs = get_block_wrapper_attributes(
			array(
				'class' => 'bw-dev-post-link bw-dev-post-link--' . $layout,
				'style' => '--bw-dev-post-link-img-width: ' . $img_width . '%;',
			)
		);

		return sprintf( '<ul %1$s>%2$s</ul>', $wrapper_attrs, $content );
	}

	public function render_item( $attributes ): string {
		$type = ! empty( $attributes['linkType'] ) ? $attributes['linkType'] : 'internal';

		$title    = '';
		$url      = '';
		$thumb_id = 0;
		$target   = '';
		$rel      = '';

		if ( 'external' === $type ) {
			$title    = isset( $attributes['externalTitle'] ) ? trim( (string) $attributes['externalTitle'] ) : '';
			$url      = isset( $attributes['externalUrl'] ) ? esc_url_raw( (string) $attributes['externalUrl'] ) : '';
			$thumb_id = isset( $attributes['externalThumbnailId'] ) ? (int) $attributes['externalThumbnailId'] : 0;
			$target   = ' target="_blank"';
			$rel      = ' rel="noopener noreferrer"';
		} else {
			$post_id = isset( $attributes['postId'] ) ? (int) $attributes['postId'] : 0;
			if ( ! $post_id ) {
				return '';
			}
			$post = get_post( $post_id );
			if ( ! $post || 'publish' !== $post->post_status ) {
				return '';
			}

			$custom_title = isset( $attributes['customTitle'] ) ? trim( (string) $attributes['customTitle'] ) : '';
			$title        = '' !== $custom_title ? $custom_title : get_the_title( $post );
			$url          = (string) get_permalink( $post );

			$custom_thumb_id = isset( $attributes['customThumbnailId'] ) ? (int) $attributes['customThumbnailId'] : 0;
			$thumb_id        = $custom_thumb_id ? $custom_thumb_id : (int) get_post_thumbnail_id( $post );
		}

		if ( '' === $title || '' === $url ) {
			return '';
		}

		if ( $thumb_id ) {
			$thumb_html = wp_get_attachment_image(
				$thumb_id,
				'medium_large',
				false,
				array(
					'class'   => 'bw-dev-post-link__thumb',
					'loading' => 'lazy',
					'alt'     => '',
				)
			);
		} else {
			$thumb_html = '<span class="bw-dev-post-link__thumb bw-dev-post-link__thumb--placeholder" aria-hidden="true"></span>';
		}

		$html  = '<li class="wp-block-bw-dev-post-link-item bw-dev-post-link__item">';
		$html .= '<a class="bw-dev-post-link__link" href="' . esc_url( $url ) . '"' . $target . $rel . '>';
		$html .= '<span class="bw-dev-post-link__thumb-wrap">' . $thumb_html . '</span>';
		$html .= '<span class="bw-dev-post-link__title">' . esc_html( $title ) . '</span>';
		$html .= '</a>';
		$html .= '</li>';

		return $html;
	}

	public function render_tab(): void {
		?>
		<p class="description">
			<?php esc_html_e( 'This module has no settings. It registers two Gutenberg blocks for displaying nicely-rendered post links.', 'bw-dev' ); ?>
		</p>

		<h3><?php esc_html_e( 'How to use', 'bw-dev' ); ?></h3>
		<ol>
			<li><?php esc_html_e( 'In any post or page, open the block inserter (the + button).', 'bw-dev' ); ?></li>
			<li>
				<?php
				printf(
					/* translators: %s: parent block name in bold */
					esc_html__( 'Insert the %s block. Each list comes with one empty item — fill it in from the sidebar, then add more items with the appender.', 'bw-dev' ),
					'<strong>' . esc_html__( 'BW Post Link List', 'bw-dev' ) . '</strong>'
				);
				?>
			</li>
			<li><?php esc_html_e( 'Each item can be an internal post (pick from any public post type) or an external URL.', 'bw-dev' ); ?></li>
		</ol>

		<h3><?php esc_html_e( 'Layouts', 'bw-dev' ); ?></h3>
		<ul style="list-style:disc; margin-left:20px;">
			<li><strong><?php esc_html_e( 'Simple', 'bw-dev' ); ?></strong> — <?php esc_html_e( 'plain bulleted list of text links. Thumbnails are hidden.', 'bw-dev' ); ?></li>
			<li><strong><?php esc_html_e( 'Thumbnail', 'bw-dev' ); ?></strong> — <?php esc_html_e( 'one row per item with a 16:9 thumbnail and title side-by-side. Thumbnail width is configurable (10–60% of the row).', 'bw-dev' ); ?></li>
		</ul>

		<h3><?php esc_html_e( 'REST endpoint', 'bw-dev' ); ?></h3>
		<p class="description">
			<?php
			printf(
				/* translators: %s: REST route */
				esc_html__( 'The block editor calls %s to list public post types. Requires the edit_posts capability.', 'bw-dev' ),
				'<code>GET /wp-json/' . esc_html( self::REST_NAMESPACE ) . '/post-types</code>'
			);
			?>
		</p>
		<?php
	}

	public function uninstall(): void {
		// No-op.
	}
}
