<?php
/**
 * Download PDF button block renderer.
 *
 * @package PDFDraft
 */

namespace PDFDraft;

use PDFDraft\Blocks\BlockRegistrar;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly.
}

/**
 * Provides a "Download PDF" dynamic block.
 */
class DownloadPdf {
	/**
	 * Block name.
	 *
	 * @var string
	 */
	private const BLOCK_NAME = 'pdfdraft/download-pdf';

	/**
	 * Init hooks.
	 *
	 * @return void
	 */
	public function init(): void {
		add_action( 'init', array( $this, 'registerBlocks' ) );
		add_action( 'enqueue_block_editor_assets', array( $this, 'enqueueBlockEditorAssets' ) );
	}

	/**
	 * Register dynamic block.
	 *
	 * @return void
	 */
	public function registerBlocks(): void {
		( new BlockRegistrar() )->registerBlocks( $this->getServerBlockDefinitions() );
	}

	/**
	 * Enqueue block editor assets.
	 *
	 * @return void
	 */
	public function enqueueBlockEditorAssets(): void {
		( new BlockRegistrar() )->registerAndEnqueueEditorScripts( $this->getEditorBlockScriptDefinitions() );
	}

	/**
	 * Server block definitions.
	 *
	 * @return array<int, array{name:string,args:array}>
	 */
	private function getServerBlockDefinitions(): array {
		return array(
			array(
				'name' => self::BLOCK_NAME,
				'args' => array(
					'api_version'     => 3,
					'editor_script'   => 'pdfdraft-download-pdf-block',
					'render_callback' => array( $this, 'renderBlock' ),
					'attributes'      => array(
						'templateId' => array( 'type' => 'string' ),
						'text'       => array( 'type' => 'string' ),
	
						'borderRadius'        => array( 'type' => 'string', 'default' => '' ),
						'contentJustification' => array( 'type' => 'string', 'default' => 'left' ),
						'buttonWidth'          => array( 'type' => 'number' ),
					),
					'supports'        => array(
						'html'       => false,
						'align'      => true,
						'color'      => array(
							'background' => true,
							'gradients'  => true,
							'text'       => true,
						),
						'spacing'    => array(
							'padding' => true,
							'margin'  => true,
						),
						'border'     => array(
							'color'  => true,
							'radius' => true,
							'style'  => true,
							'width'  => true,
						),
						'typography' => array(
							'fontSize'   => true,
							'lineHeight' => true,
						),
					),
				),
			),
		);
	}

	/**
	 * Editor script registry definitions.
	 *
	 * @return array<int, array<string,mixed>>
	 */
	private function getEditorBlockScriptDefinitions(): array {
		return array(
			array(
				'handle'     => 'pdfdraft-download-pdf-block',
				'src'        => trailingslashit( PDFDRAFT_DIST_URI ) . 'download-pdf-block.js',
				'asset_file' => PDFDRAFT_DIST_DIR . '/download-pdf-block.asset.php',
				'deps'       => array(
					'wp-blocks',
					'wp-element',
					'wp-i18n',
					'wp-components',
					'wp-block-editor',
					'wp-api-fetch',
				),
			),
		);
	}

	/**
	 * Render dynamic block.
	 *
	 * @param array<string,mixed> $attributes Block attributes.
	 * @param string              $content Block content.
	 * @param \WP_Block|null      $block Block instance.
	 * @return string
	 */
	public function renderBlock( array $attributes = array(), string $content = '', $block = null ): string {
		unset( $content, $block );
		$template = sanitize_title( (string) ( $attributes['templateId'] ?? '' ) );
		if ( '' === $template ) {
			return '';
		}
		if ( ! $this->templateDesignExists( $template ) ) {
			return '';
		}

		$text = trim( (string) ( $attributes['text'] ?? '' ) );
		if ( '' === $text ) {
			$text = __( 'Download PDF', 'pdfdraft' );
		}

		$config_id      = 'pdfdraft-download-' . wp_unique_id();
		$dynamic_config = $this->buildDynamicPdfConfig( $template );

		$ajax = admin_url( 'admin-ajax.php' );
		$url  = add_query_arg(
			array(
				'action'   => 'pdfdraft_embed_pdf',
				'slug'     => $template,
				'download' => 1,
			),
			$ajax
		);


		// WordPress applies block-support styles (color, spacing, border) to the wrapper via
		// get_block_wrapper_attributes(). We need those on the <a> instead. Extract them here.
		$raw_wrapper = function_exists( 'get_block_wrapper_attributes' )
			? get_block_wrapper_attributes( array( 'class' => 'wp-block-button' ) )
			: 'class="wp-block-button"';

		// Pull inline style out of wrapper → move to <a>.
		$button_inline_style = '';
		$wrapper_attrs       = preg_replace_callback(
			'/\bstyle="([^"]*)"/',
			function ( array $m ) use ( &$button_inline_style ): string {
				$button_inline_style = $m[1];
				return '';
			},
			$raw_wrapper
		) ?? $raw_wrapper;

		// Pull has-* classes (color/font semantics) out of wrapper → move to <a>.
		$button_extra_classes = '';
		$wrapper_attrs        = preg_replace_callback(
			'/\bclass="([^"]*)"/',
			function ( array $m ) use ( &$button_extra_classes ): string {
				$all  = preg_split( '/\s+/', trim( $m[1] ) ) ?: array();
				$keep = array();
				$take = array();
				foreach ( $all as $c ) {
					if ( '' === $c ) {
						continue;
					}
					if ( 0 === strpos( $c, 'has-' ) ) {
						$take[] = $c;
					} else {
						$keep[] = $c;
					}
				}
				$button_extra_classes = implode( ' ', $take );
				return 'class="' . implode( ' ', $keep ) . '"';
			},
			$wrapper_attrs
		) ?? $wrapper_attrs;

		$button_class = trim( 'wp-block-button__link wp-element-button ' . $button_extra_classes );

		$border_radius = trim( (string) ( $attributes['borderRadius'] ?? '' ) );
		if ( '' !== $border_radius ) {
			$button_inline_style = trim( $button_inline_style . ';border-radius:' . esc_attr( $border_radius ) . ';', ';' );
		}

		$button_width = isset( $attributes['buttonWidth'] ) ? (int) $attributes['buttonWidth'] : 0;
		if ( $button_width > 0 && $button_width <= 100 ) {
			$button_inline_style = trim( $button_inline_style . ';width:' . $button_width . '%;', ';' );
		}

		$style_attr = '' !== $button_inline_style
			? ' style="' . esc_attr( $button_inline_style ) . '"'
			: '';

		$justify_map   = array( 'left' => 'flex-start', 'center' => 'center', 'right' => 'flex-end' );
		$justify_value = $justify_map[ (string) ( $attributes['contentJustification'] ?? 'left' ) ] ?? 'flex-start';
		$wrapper_attrs = trim( $wrapper_attrs ) . ' style="display:flex;justify-content:' . esc_attr( $justify_value ) . ';"';

		$this->maybeEnqueueFrontendAssets();
		if ( null !== $dynamic_config ) {
			$this->enqueueDynamicPdfAssets( $config_id, $dynamic_config );
		}

		return sprintf(
			'<div %1$s><a class="%2$s" href="%3$s" download%4$s data-pdfdraft-download data-pdfdraft-dynamic-download="%7$s" data-pdfdraft-config-id="%8$s" data-post-id="%9$d" data-slug="%5$s"><span class="pdfdraft-dl-text">%6$s</span><span class="pdfdraft-dl-spinner" aria-hidden="true"></span></a></div>',
			trim( $wrapper_attrs ),
			esc_attr( $button_class ),
			esc_url( $url ),
			$style_attr,
			esc_attr( $template ),
			wp_kses_post( $text ),
			null !== $dynamic_config ? '1' : '0',
			esc_attr( $config_id ),
			(int) get_the_ID()
		);
	}

	/**
	 * Build frontend generation config for dynamic WP data fields.
	 *
	 * @param string $template Template slug.
	 * @return array<string,mixed>|null
	 */
	private function buildDynamicPdfConfig( string $template ): ?array {
		$design = get_page_by_path( $template, OBJECT, 'pdfdraft-design' );
		if ( ! $this->isUsableDesignPost( $design ) ) {
			return null;
		}

		$decoded = json_decode( $design->post_content, true );
		if ( ! is_array( $decoded ) ) {
			return null;
		}

		return array(
			'postId'          => (int) get_the_ID(),
			'templateData'    => $decoded,
			'filenamePattern' => '{post_title}.pdf',
			'includeImages'   => true,
			'fontFamily'      => 'Inter',
			'restUrl'         => rest_url(),
			'nonce'           => wp_create_nonce( 'wp_rest' ),
		);
	}

	/**
	 * Check whether a template slug still belongs to an active design post.
	 *
	 * @param string $slug Template/design slug.
	 * @return bool
	 */
	private function templateDesignExists( string $slug ): bool {
		return $this->isUsableDesignPost(
			get_page_by_path( sanitize_title( $slug ), OBJECT, 'pdfdraft-design' )
		);
	}

	/**
	 * Check whether a post object is a usable design.
	 *
	 * @param mixed $post Candidate post.
	 * @return bool
	 */
	private function isUsableDesignPost( $post ): bool {
		return $post instanceof \WP_Post
			&& 'pdfdraft-design' === $post->post_type
			&& ! in_array( $post->post_status, array( 'trash', 'auto-draft' ), true );
	}

	/**
	 * Enqueue the browser generator used by Posts to PDF and attach this block config.
	 *
	 * @param string              $config_id Config id.
	 * @param array<string,mixed> $config Config payload.
	 * @return void
	 */
	private function enqueueDynamicPdfAssets( string $config_id, array $config ): void {
		if ( ! wp_script_is( 'pdfdraft-posts-to-pdf-frontend', 'registered' ) ) {
			return;
		}

		wp_add_inline_script(
			'pdfdraft-posts-to-pdf-frontend',
			"window.__PDFDRAFT__ = window.__PDFDRAFT__ || { defaultFont: { family: 'Inter' } };",
			'before'
		);
		wp_add_inline_script(
			'pdfdraft-posts-to-pdf-frontend',
			'window.__PDFDRAFT_DYNAMIC_PDFS__ = window.__PDFDRAFT_DYNAMIC_PDFS__ || {}; window.__PDFDRAFT_DYNAMIC_PDFS__[' . wp_json_encode( $config_id ) . '] = ' . wp_json_encode( $config ) . ';',
			'before'
		);
		wp_enqueue_script( 'pdfdraft-posts-to-pdf-frontend' );
	}

	/**
	 * Enqueue frontend CSS + JS for the download button (once per page).
	 *
	 * @return void
	 */
	private function maybeEnqueueFrontendAssets(): void {
		if ( ! wp_style_is( 'pdfdraft-download-btn', 'registered' ) ) {
			wp_register_style( 'pdfdraft-download-btn', false, array(), PDFDRAFT_VERSION );
			wp_add_inline_style( 'pdfdraft-download-btn', $this->getFrontendStyles() );
		}
		wp_enqueue_style( 'pdfdraft-download-btn' );

		if ( ! wp_script_is( 'pdfdraft-download-btn', 'registered' ) ) {
			wp_register_script( 'pdfdraft-download-btn', false, array(), PDFDRAFT_VERSION, true );
			wp_add_inline_script( 'pdfdraft-download-btn', $this->getFrontendScript() );
		}
		wp_enqueue_script( 'pdfdraft-download-btn' );
	}

	/**
	 * Inline CSS for the spinner.
	 *
	 * @return string
	 */
	private function getFrontendStyles(): string {
		return '
[data-pdfdraft-download]{text-align:center;box-sizing:border-box;}
.pdfdraft-dl-spinner{display:none;width:1em;height:1em;border:.15em solid currentColor;border-top-color:transparent;border-radius:50%;animation:pdfdraft-spin .65s linear infinite;vertical-align:middle;margin-left:.45em;}
[data-pdfdraft-download].pdfdraft-loading{opacity:.7;pointer-events:none;cursor:default;}
[data-pdfdraft-download].pdfdraft-loading .pdfdraft-dl-spinner{display:inline-block;}
@keyframes pdfdraft-spin{to{transform:rotate(360deg);}}
';
	}

	/**
	 * Inline JS for the click-to-download with loading state.
	 *
	 * @return string
	 */
	private function getFrontendScript(): string {
		return '
(function(){
	function initBtn(btn){
		btn.addEventListener("click",function(e){
			if(btn.dataset.pdfdraftDynamicDownload==="1") return;
			e.preventDefault();
			if(btn.classList.contains("pdfdraft-loading")) return;
			btn.classList.add("pdfdraft-loading");
			var slug=btn.dataset.slug||"download";
			fetch(btn.getAttribute("href"))
				.then(function(r){
					if(!r.ok) throw new Error("HTTP "+r.status);
					return r.blob();
				})
				.then(function(blob){
					var url=URL.createObjectURL(blob);
					var a=document.createElement("a");
					a.href=url;
					a.download=slug+".pdf";
					document.body.appendChild(a);
					a.click();
					document.body.removeChild(a);
					setTimeout(function(){URL.revokeObjectURL(url);},100);
				})
				.catch(function(){})
				.finally(function(){
					btn.classList.remove("pdfdraft-loading");
				});
		});
	}
	function init(){
		document.querySelectorAll("[data-pdfdraft-download]").forEach(initBtn);
	}
	if(document.readyState==="loading"){
		document.addEventListener("DOMContentLoaded",init);
	} else {
		init();
	}
})();
';
	}
}
