<?php
/**
 * Injects the download button into post/page content.
 *
 * @package PDFDraft
 */

namespace PDFDraft\PostsToPdf;

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

use PDFDraft\PostsToPdf\Settings as PostsToPdfSettings;

/**
 * Hooks into the_content to append/prepend a download button.
 * Also registers [pdfdraft_download_pdf] shortcode.
 */
class ButtonInjector {

	/**
	 * @var PostsToPdfSettings
	 */
	private PostsToPdfSettings $settings;

	/**
	 * Constructor.
	 *
	 * @param PostsToPdfSettings $settings Settings service.
	 */
	public function __construct( PostsToPdfSettings $settings ) {
		$this->settings = $settings;
	}

	/**
	 * Register hooks.
	 *
	 * @return void
	 */
	public function init(): void {
		add_filter( 'the_content', array( $this, 'inject_button' ) );
		add_shortcode( 'pdfdraft_download_pdf', array( $this, 'shortcode' ) );
	}

	/**
	 * Filter callback — injects the button before/after post content.
	 *
	 * @param string $content Original post content.
	 * @return string
	 */
	public function inject_button( string $content ): string {
		if ( ! $this->should_inject() ) {
			return $content;
		}

		$position = $this->settings->get_all()['button']['position'] ?? 'after_content';
		$html     = $this->render_button_html();

		if ( 'before_content' === $position ) {
			return $html . $content;
		}

		if ( 'floating' === $position ) {
			return $content . $this->render_floating_button_html();
		}

		// Default: after_content
		return $content . $html;
	}

	/**
	 * Shortcode handler: [pdfdraft_download_pdf]
	 *
	 * @param array $atts Shortcode attributes.
	 * @return string
	 */
	public function shortcode( $atts ): string {
		$atts = shortcode_atts(
			array(
				'post_id'     => 0,
				'text'        => '',
				'class'       => '',
				'template_id' => '',
				'design_id'   => '',
			),
			$atts,
			'pdfdraft_download_pdf'
		);

		$settings   = $this->settings->get_all();
		$button_text = $atts['text'] ?: $settings['button']['text'];
		$css_class   = $atts['class'] ?: $settings['button']['css_class'];
		$template_ref = (string) ( $atts['template_id'] ?: $atts['design_id'] );
		$template_slug = $this->resolve_template_slug( $template_ref );

		// Allow shortcode usage with an explicit design/template identifier:
		// [pdfdraft_download_pdf template_id="design-slug-or-id"].
		if ( '' !== $template_slug ) {
			return $this->render_template_download_html( $template_slug, $button_text, $css_class );
		}

		$post_id = $atts['post_id'] ? (int) $atts['post_id'] : get_the_ID();
		if ( ! $post_id ) {
			return '';
		}

		return $this->render_button_html( $post_id, $button_text, $css_class );
	}

	// ── Private helpers ───────────────────────────────────────────────────────

	/**
	 * Determine whether the button should be injected on this request.
	 *
	 * @return bool
	 */
	private function should_inject(): bool {
		// Only on singular post / page views in the main loop.
		if ( ! is_singular() || ! in_the_loop() || ! is_main_query() ) {
			return false;
		}

		$post_type = get_post_type();
		$settings  = $this->settings->get_all();

		if ( ! $settings['enabled'] ) {
			return false;
		}

		// Per-post visibility override.
		$visibility = get_post_meta( get_the_ID(), '_pdfdraft_pdf_button_visibility', true ) ?: 'global';
		if ( 'hide' === $visibility ) {
			return false;
		}
		if ( 'show' === $visibility ) {
			return true;
		}

		// Global setting per post type.
		if ( 'post' === $post_type && ! empty( $settings['posts']['enabled'] ) ) {
			return $this->is_pdf_configured( $settings['posts'] );
		}

		if ( 'page' === $post_type && ! empty( $settings['pages']['enabled'] ) ) {
			return $this->is_pdf_configured( $settings['pages'] );
		}

		return false;
	}

	/**
	 * Render the button HTML.
	 *
	 * @param int|null    $post_id     Post ID (defaults to current post).
	 * @param string|null $button_text Button label (defaults to settings value).
	 * @param string|null $css_class   Extra CSS class (defaults to settings value).
	 * @return string
	 */
	private function render_button_html(
		?int    $post_id     = null,
		?string $button_text = null,
		?string $css_class   = null
	): string {
		$post_id     = $post_id ?? (int) get_the_ID();
		$settings    = $this->settings->get_all();
		$button_text = $button_text ?? esc_html( $settings['button']['text'] );
		$css_class   = $this->normalize_css_classes( (string) ( $css_class ?? $settings['button']['css_class'] ) );
		$class_attr  = $this->get_theme_button_classes( $css_class );

		return sprintf(
			'<div class="pdfdraft-posts-to-pdf-wrap wp-block-button">
				<button
					type="button"
					class="%6$s"
					data-post-id="%1$d"
					data-button-text="%2$s"
					data-css-class="%6$s"
					data-post-type="%4$s"
				>%5$s</button>
			</div>',
			esc_attr( $post_id ),
			esc_attr( $button_text ),
			esc_attr( $class_attr ),
			esc_attr( (string) get_post_type( $post_id ) ),
			esc_html( $button_text ),
			esc_attr( $class_attr )
		);
	}

	/**
	 * Render a floating button (position: fixed, bottom-right).
	 *
	 * @return string
	 */
	private function render_floating_button_html(): string {
		$settings  = $this->settings->get_all();
		$post_id   = (int) get_the_ID();
		$btn_text  = esc_html( $settings['button']['text'] );
		$css_class = $this->normalize_css_classes( (string) $settings['button']['css_class'] );
		$class_attr = $this->get_theme_button_classes( $css_class );

		return sprintf(
			'<div
				class="pdfdraft-posts-to-pdf-wrap pdfdraft-posts-to-pdf-floating wp-block-button"
				style="position:fixed;bottom:24px;right:24px;z-index:9999"
			>
				<button
					type="button"
					class="%6$s"
					data-post-id="%1$d"
					data-button-text="%2$s"
					data-css-class="%6$s"
					data-post-type="%4$s"
				>%5$s</button>
			</div>',
			esc_attr( $post_id ),
			esc_attr( $btn_text ),
			esc_attr( $class_attr ),
			esc_attr( (string) get_post_type( $post_id ) ),
			$btn_text,
			esc_attr( $class_attr )
		);
	}

	/**
	 * Return true when a post-type settings array has enough configuration to
	 * show the download button. In 'default' mode no project is required; in
	 * 'custom' mode a project_id must be set.
	 *
	 * @param array $pt_settings Post-type settings (posts or pages).
	 * @return bool
	 */
	private function is_pdf_configured( array $pt_settings ): bool {
		// Button shows whenever the post type is enabled.
		// 'custom' with no project falls back to default-mode rendering in JS.
		return true;
	}

	/**
	 * Normalize a whitespace-separated class string to safe HTML classes.
	 *
	 * @param string $classes Raw class string.
	 * @return string
	 */
	private function normalize_css_classes( string $classes ): string {
		$parts = preg_split( '/\s+/', trim( $classes ) ) ?: array();
		$parts = array_map( 'sanitize_html_class', $parts );
		$parts = array_filter( $parts, static fn( $class ) => is_string( $class ) && '' !== $class );
		return implode( ' ', $parts );
	}

	/**
	 * Build classes that inherit the active theme's default button styling.
	 *
	 * @param string $extra_classes User-configured CSS classes.
	 * @return string
	 */
	private function get_theme_button_classes( string $extra_classes = '' ): string {
		return trim( 'pdfdraft-download-pdf-btn wp-block-button__link wp-element-button ' . $extra_classes );
	}

	/**
	 * Resolve a template reference (slug or numeric post ID) to a design slug.
	 *
	 * @param string $template_ref Template reference from shortcode attrs.
	 * @return string
	 */
	private function resolve_template_slug( string $template_ref ): string {
		$template_ref = trim( $template_ref );
		if ( '' === $template_ref ) {
			return '';
		}

		if ( ctype_digit( $template_ref ) ) {
			$post_id = (int) $template_ref;
			$post    = get_post( $post_id );
			if ( $post && 'pdfdraft-design' === $post->post_type ) {
				return sanitize_title( $post->post_name );
			}
		}

		return sanitize_title( $template_ref );
	}

	/**
	 * Render direct template download HTML.
	 *
	 * @param string      $template_slug Design slug.
	 * @param string|null $button_text Button label.
	 * @param string|null $css_class Extra CSS class.
	 * @return string
	 */
	private function render_template_download_html(
		string  $template_slug,
		?string $button_text = null,
		?string $css_class = null
	): string {
		if ( '' === $template_slug ) {
			return '';
		}
		if ( ! $this->template_design_exists( $template_slug ) ) {
			return '';
		}

		$settings    = $this->settings->get_all();
		$button_text = $button_text ?? esc_html( $settings['button']['text'] );
		$css_class   = $this->normalize_css_classes( (string) ( $css_class ?? $settings['button']['css_class'] ) );
		$class_attr  = $this->get_theme_button_classes( $css_class );
		$config_id   = 'pdfdraft-shortcode-download-' . wp_unique_id();
		$dynamic_config = $this->build_dynamic_pdf_config( $template_slug );
		$use_dynamic    = null !== $dynamic_config && $this->enqueue_dynamic_pdf_assets( $config_id, $dynamic_config );
		$url         = add_query_arg(
			array(
				'action'   => 'pdfdraft_embed_pdf',
				'slug'     => $template_slug,
				'download' => 1,
			),
			admin_url( 'admin-ajax.php' )
		);

		return sprintf(
			'<div class="pdfdraft-posts-to-pdf-wrap wp-block-button"><a class="%1$s" href="%2$s" download data-pdfdraft-download data-pdfdraft-dynamic-download="%4$s" data-pdfdraft-config-id="%5$s" data-post-id="%6$d" data-slug="%7$s"><span class="pdfdraft-dl-text">%3$s</span><span class="pdfdraft-dl-spinner" aria-hidden="true"></span></a></div>',
			esc_attr( $class_attr ),
			esc_url( $url ),
			esc_html( $button_text ),
			$use_dynamic ? '1' : '0',
			esc_attr( $config_id ),
			(int) get_the_ID(),
			esc_attr( $template_slug )
		);
	}

	/**
	 * Build frontend PDF generation config for explicit template shortcode downloads.
	 *
	 * @param string $template_slug Design slug.
	 * @return array<string,mixed>|null
	 */
	private function build_dynamic_pdf_config( string $template_slug ): ?array {
		$design = get_page_by_path( $template_slug, OBJECT, 'pdfdraft-design' );
		if ( ! $this->is_usable_design_post( $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 template_design_exists( string $slug ): bool {
		return $this->is_usable_design_post(
			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 is_usable_design_post( $post ): bool {
		return $post instanceof \WP_Post
			&& 'pdfdraft-design' === $post->post_type
			&& ! in_array( $post->post_status, array( 'trash', 'auto-draft' ), true );
	}

	/**
	 * Enqueue browser-side PDF generation for shortcode template downloads.
	 *
	 * @param string              $config_id Config id.
	 * @param array<string,mixed> $config Config payload.
	 * @return bool Whether dynamic generation was enqueued.
	 */
	private function enqueue_dynamic_pdf_assets( string $config_id, array $config ): bool {
		if ( ! wp_script_is( 'pdfdraft-posts-to-pdf-frontend', 'registered' ) ) {
			return false;
		}

		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' );

		return true;
	}
}
