<?php
/**
 * Fundraiser QR Code Block
 *
 * Renders an inline SVG QR code linking to a fundraiser using
 * chillerlan/php-qrcode. No external service calls.
 *
 * @package AmbassadorHub\Fundraisers\Blocks\QRCode
 */

namespace AmbassadorHub\Fundraisers\Blocks\QRCode;

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

use AmbassadorHub\Fundraisers\FundraisersModule;
use chillerlan\QRCode\QRCode;
use chillerlan\QRCode\QROptions;

/**
 * QR Code block registration and rendering.
 */
final class Block {
	/**
	 * Initialize the block.
	 *
	 * @return void
	 */
	public static function init(): void {
		add_action( 'init', array( self::class, 'register_block' ) );
	}

	/**
	 * Register the block.
	 *
	 * @return void
	 */
	public static function register_block(): void {
		$handle    = 'ambh-fundraiser-qr-code-block';
		$block_dir = AMBASSADOR_HUB_PATH . 'src/Fundraisers/Blocks/QRCode/';
		$block_url = AMBASSADOR_HUB_URL . 'src/Fundraisers/Blocks/QRCode/';

		$script_file = $block_dir . 'index.js';
		if ( file_exists( $script_file ) ) {
			wp_register_script(
				$handle,
				$block_url . 'index.js',
				array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-server-side-render' ),
				filemtime( $script_file ),
				true
			);
		}

		wp_register_style(
			'ambh-fundraiser-qr-code',
			$block_url . 'style.css',
			array(),
			AMBASSADOR_HUB_VERSION
		);

		$block_args = array(
			'style'           => 'ambh-fundraiser-qr-code',
			'render_callback' => array( self::class, 'render_block' ),
		);

		if ( file_exists( $script_file ) ) {
			$block_args['editor_script'] = $handle;
		}

		register_block_type( $block_dir, $block_args );

		add_shortcode( 'ambh_fundraiser_qr_code', array( self::class, 'render_shortcode' ) );
	}

	/**
	 * Render the block.
	 *
	 * Returns a bare <svg> element. Wrapper markup and titles are handled
	 * by the consuming template.
	 *
	 * @param array $attributes Block attributes.
	 *
	 * @return string Inline SVG markup.
	 */
	public static function render_block( $attributes ): string {
		$fundraiser_id = isset( $attributes['fundraiserId'] ) ? absint( $attributes['fundraiserId'] ) : 0;
		$size          = isset( $attributes['size'] ) ? absint( $attributes['size'] ) : 200;
		$query_params  = isset( $attributes['queryParams'] ) ? trim( $attributes['queryParams'] ) : '';

		if ( ! $fundraiser_id ) {
			$fundraiser_id = get_the_ID();
		}

		$fundraiser = get_post( $fundraiser_id );
		if ( ! $fundraiser || FundraisersModule::POST_TYPE !== $fundraiser->post_type || 'publish' !== $fundraiser->post_status ) {
			if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
				return '<div style="padding: 20px; background: #f0f0f1; border: 1px solid #ddd; text-align: center;">'
					. esc_html__( 'Geen geldige fundraiser geselecteerd.', 'ambassadorhub' )
					. '</div>';
			}
			return '';
		}

		$fundraiser_url = get_permalink( $fundraiser_id );

		if ( ! empty( $query_params ) ) {
			$query_params = ltrim( $query_params, '?&' );
			parse_str( $query_params, $params_array );
			$fundraiser_url = add_query_arg( $params_array, $fundraiser_url );
		}

		$size = max( 100, min( 500, $size ) );

		$options = new QROptions();

		// phpcs:disable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase -- QROptions is a third-party class (chillerlan/php-qrcode); its public property names are part of that library's API and must not be renamed.
		$options->outputBase64    = false;
		$options->svgAddXmlHeader = false;
		$options->svgViewBoxSize  = $size;
		$options->addQuietzone    = true;
		$options->quietzoneSize   = 2;
		// phpcs:enable WordPress.NamingConventions.ValidVariableName.UsedPropertyNotSnakeCase

		$svg = ( new QRCode( $options ) )->render( $fundraiser_url );

		return wp_kses( $svg, self::allowed_svg_tags() );
	}

	/**
	 * Allowed tags/attributes for the QR code SVG markup.
	 *
	 * Matches exactly what chillerlan/php-qrcode's SVG output writer emits
	 * (see vendor/chillerlan/php-qrcode/src/Output/QRMarkupSVG.php): a
	 * single <svg> wrapper, an optional (here always-empty) <defs>, and one
	 * or more <path> elements whose "d" data is computed purely from the QR
	 * module grid — the URL text itself never appears in the output.
	 *
	 * @return array<string, array<string, bool>>
	 */
	private static function allowed_svg_tags(): array {
		return array(
			'svg'  => array(
				'xmlns'               => true,
				'class'               => true,
				'viewbox'             => true,
				'preserveaspectratio' => true,
			),
			'defs' => array(),
			'path' => array(
				'class' => true,
				'fill'  => true,
				'd'     => true,
			),
		);
	}

	/**
	 * Render shortcode.
	 *
	 * @param array $atts Shortcode attributes.
	 *
	 * @return string Inline SVG markup.
	 */
	public static function render_shortcode( $atts ): string {
		$attributes = shortcode_atts(
			array(
				'id'     => 0,
				'size'   => 200,
				'params' => '',
			),
			$atts
		);

		return self::render_block(
			array(
				'fundraiserId' => absint( $attributes['id'] ),
				'size'         => absint( $attributes['size'] ),
				'queryParams'  => $attributes['params'],
			)
		);
	}
}
