<?php
/**
 * Front-end display of the cached AI summary and FAQ data: automatic
 * placement, the [priizmo_summary]/[priizmo_faq] shortcodes, JSON-LD FAQPage
 * schema, and custom CSS output.
 *
 * @package Priizmo_Engine
 */

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

/**
 * Class Priizmo_Engine_Display
 */
class Priizmo_Engine_Display {

	/**
	 * Constructor. Hooks the content filters, shortcodes, and head output.
	 */
	public function __construct() {
		add_filter( 'the_content', array( $this, 'maybe_insert_summary' ), 20 );
		add_filter( 'the_content', array( $this, 'maybe_append_faq' ), 25 );
		add_shortcode( 'priizmo_summary', array( $this, 'render_summary_shortcode' ) );
		add_shortcode( 'priizmo_faq', array( $this, 'render_faq_shortcode' ) );
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueue_frontend_styles' ) );

		// FAQPage JSON-LD structured data is fully available to every user,
		// free or paid: WordPress.org's Plugin Directory Guidelines (5)
		// prohibit locking or limiting any built-in feature behind a
		// license/upgrade check, even when the feature would otherwise be
		// "free to use, just gated." This used to be wrapped in an
		// priizmo_engine_is_pro() check; Bulk Processing (a Pro-only feature
		// that is instead *entirely absent* from the free distribution's
		// files, rather than present-but-disabled) remains the only
		// difference between the free and premium builds.
		add_action( 'wp_head', array( $this, 'output_faq_schema' ) );
	}

	/**
	 * Inserts the cached summary into post content automatically, based on
	 * the "Summary Display Location" setting.
	 *
	 * @param string $content Post content.
	 *
	 * @return string
	 */
	public function maybe_insert_summary( $content ) {
		if ( ! is_singular( 'post' ) || ! in_the_loop() || ! is_main_query() ) {
			return $content;
		}

		$location = Priizmo_Engine::get_setting( 'summary_display_location', 'shortcode_only' );

		if ( 'shortcode_only' === $location ) {
			return $content;
		}

		$summary = get_post_meta( get_the_ID(), Priizmo_Engine_Post_Meta::META_KEY, true );

		if ( empty( $summary ) ) {
			return $content;
		}

		$box = self::render_summary_box( $summary );

		if ( 'before_h2' === $location ) {
			if ( preg_match( '/<h2[^>]*>/i', $content, $matches, PREG_OFFSET_CAPTURE ) ) {
				$position = $matches[0][1];

				return substr( $content, 0, $position ) . $box . substr( $content, $position );
			}

			// No H2 found; fall back to placing it above the content.
			return $box . $content;
		}

		// Default: 'above_content'.
		return $box . $content;
	}

	/**
	 * Appends the cached FAQ block to the very bottom of singular post
	 * content, unless the post already places it manually via the
	 * [priizmo_faq] shortcode.
	 *
	 * @param string $content Post content (already passed through
	 *                        maybe_insert_summary() and do_shortcode()).
	 *
	 * @return string
	 */
	public function maybe_append_faq( $content ) {
		if ( ! is_singular( 'post' ) || ! in_the_loop() || ! is_main_query() ) {
			return $content;
		}

		$post_id = get_the_ID();

		if ( ! $post_id ) {
			return $content;
		}

		// If the author already placed [priizmo_faq] in the raw stored content,
		// honor that manual placement instead of appending a second copy.
		$raw_content = get_post_field( 'post_content', $post_id );

		if ( has_shortcode( $raw_content, 'priizmo_faq' ) ) {
			return $content;
		}

		$faq_items = Priizmo_Engine_Post_Meta::get_faq_items( $post_id );

		if ( empty( $faq_items ) ) {
			return $content;
		}

		return $content . self::render_faq_block( $faq_items );
	}

	/**
	 * Renders the [priizmo_summary] shortcode.
	 *
	 * @return string
	 */
	public function render_summary_shortcode() {
		$post_id = get_the_ID();

		if ( ! $post_id ) {
			return '';
		}

		$summary = get_post_meta( $post_id, Priizmo_Engine_Post_Meta::META_KEY, true );

		if ( empty( $summary ) ) {
			return '';
		}

		return self::render_summary_box( $summary );
	}

	/**
	 * Renders the [priizmo_faq] shortcode.
	 *
	 * @return string
	 */
	public function render_faq_shortcode() {
		$post_id = get_the_ID();

		if ( ! $post_id ) {
			return '';
		}

		return self::render_faq_block( Priizmo_Engine_Post_Meta::get_faq_items( $post_id ) );
	}

	/**
	 * Builds the markup for the summary box, shared by the automatic
	 * content filter and the shortcode.
	 *
	 * @param string $summary Cached summary text.
	 *
	 * @return string
	 */
	public static function render_summary_box( $summary ) {
		return sprintf(
			'<div class="priizmo-summary-box">%s</div>',
			wpautop( esc_html( $summary ) )
		);
	}

	/**
	 * Builds the semantic, accessible FAQ block markup shared by the
	 * automatic content filter and the [priizmo_faq] shortcode.
	 *
	 * Each question uses a <details>/<summary> disclosure widget (keyboard
	 * and screen-reader accessible without JavaScript), with the question
	 * text also wrapped in an <h3> for document outline / SEO purposes.
	 *
	 * @param array $faq_items Array of ['question' => ..., 'answer' => ...].
	 *
	 * @return string
	 */
	public static function render_faq_block( $faq_items ) {
		if ( empty( $faq_items ) ) {
			return '';
		}

		$items_html = '';

		foreach ( $faq_items as $item ) {
			if ( empty( $item['question'] ) || empty( $item['answer'] ) ) {
				continue;
			}

			$items_html .= sprintf(
				'<details class="priizmo-faq-item"><summary class="priizmo-faq-question-toggle"><h3 class="priizmo-faq-question">%s</h3></summary><div class="priizmo-faq-answer">%s</div></details>',
				esc_html( $item['question'] ),
				wpautop( esc_html( $item['answer'] ) )
			);
		}

		if ( '' === $items_html ) {
			return '';
		}

		return sprintf(
			'<div class="priizmo-faq-block"><h2 class="priizmo-faq-heading">%s</h2>%s</div>',
			esc_html__( 'Frequently Asked Questions', 'priizmo-ai-summary-faq-schema' ),
			$items_html
		);
	}

	/**
	 * Default styling for .priizmo-summary-box and .priizmo-faq-block.
	 *
	 * Deliberately theme-aware rather than a fixed, generic look: instead
	 * of hardcoding a font size/color scheme that looks identical on every
	 * site regardless of theme, this only sets the handful of properties
	 * (box background, border, spacing, radius) that a theme has no
	 * selector of its own to style, and otherwise lets the theme's own
	 * rules apply:
	 * - Heading font size/weight/color (.priizmo-faq-heading is an <h2>,
	 *   .priizmo-faq-question is an <h3>) are left unset entirely, so the
	 *   theme's own h2/h3 styling renders exactly as it would for any
	 *   other heading in the post -- this is the single biggest visual
	 *   win, since heading styling is where themes differ the most.
	 * - Body copy font-size/line-height use `inherit` rather than a fixed
	 *   px value, so answer text matches the surrounding post content's
	 *   actual rendered size instead of a value chosen independently of
	 *   the theme.
	 * - The FAQ item border color blends toward the theme's own text
	 *   color (`currentColor`) via `color-mix()`, so it reads as a subtle
	 *   variant of the theme's palette instead of a fixed WP-admin gray;
	 *   the plain hex value directly before it is a fallback for browsers
	 *   without `color-mix()` support (silently ignored, never applied,
	 *   on browsers that do support it).
	 * The summary box's background/accent colors remain explicit site
	 * settings (see get_color_override_css()) rather than theme-derived,
	 * since those are meant to be a deliberate site-owner choice.
	 *
	 * @return string
	 */
	public static function get_default_css() {
		return '.priizmo-summary-box{background:#f8f9fa;border-left:4px solid #2271b1;padding:16px 20px;margin:0 0 24px;border-radius:4px;font-size:inherit;line-height:inherit;}
.priizmo-summary-box p:last-child{margin-bottom:0;}
.priizmo-faq-block{margin:32px 0;}
.priizmo-faq-block .priizmo-faq-heading{margin-bottom:16px;}
.priizmo-faq-item{border:1px solid #dcdcde;border-color:color-mix(in srgb, currentColor 15%, transparent);border-radius:4px;margin-bottom:8px;padding:12px 16px;}
.priizmo-faq-question-toggle{cursor:pointer;list-style:none;}
.priizmo-faq-question{display:inline;margin:0;}
.priizmo-faq-answer{margin-top:8px;font-size:inherit;line-height:inherit;}
.priizmo-faq-answer p:last-child{margin-bottom:0;}';
	}

	/**
	 * Builds a small CSS override snippet from the "Summary Box Background
	 * Color" / "Summary Box Accent Color" settings, layered on top of
	 * get_default_css() via wp_add_inline_style(). Unlike the free-text
	 * "Custom Summary Box CSS" textarea this replaces, only two color
	 * values are accepted, both validated with WordPress core's
	 * sanitize_hex_color() -- there is no way for this to inject arbitrary
	 * CSS (or anything else) onto the page, since a value that isn't a
	 * well-formed #rgb/#rrggbb hex color is simply rejected in favor of
	 * the built-in default.
	 *
	 * @return string
	 */
	public static function get_color_override_css() {
		$bg_color     = sanitize_hex_color( Priizmo_Engine::get_setting( 'summary_box_bg_color', '#f8f9fa' ) );
		$accent_color = sanitize_hex_color( Priizmo_Engine::get_setting( 'summary_box_accent_color', '#2271b1' ) );

		if ( empty( $bg_color ) ) {
			$bg_color = '#f8f9fa';
		}

		if ( empty( $accent_color ) ) {
			$accent_color = '#2271b1';
		}

		return sprintf(
			'.priizmo-summary-box{background:%s;border-left-color:%s;}',
			esc_attr( $bg_color ),
			esc_attr( $accent_color )
		);
	}

	/**
	 * Registers and enqueues the summary/FAQ block styles, via
	 * wp_add_inline_style() rather than a manually echoed <style> tag.
	 * `false` as the registered style's src means it has no actual file to
	 * load -- it exists purely as a handle to attach inline CSS to, which
	 * is the documented pattern for inline-only styles that don't warrant
	 * their own static asset file.
	 */
	public function enqueue_frontend_styles() {
		wp_register_style( 'priizmo-engine-summary-style', false, array(), PRIIZMO_ENGINE_VERSION );
		wp_enqueue_style( 'priizmo-engine-summary-style' );
		wp_add_inline_style( 'priizmo-engine-summary-style', self::get_default_css() . self::get_color_override_css() );
	}

	/**
	 * Outputs JSON-LD FAQPage structured data for singular posts that have
	 * cached FAQ data, following Google's FAQPage schema guidelines:
	 * https://developers.google.com/search/docs/appearance/structured-data/faqpage
	 */
	public function output_faq_schema() {
		if ( ! is_singular( 'post' ) ) {
			return;
		}

		$post_id = get_the_ID();

		if ( ! $post_id ) {
			return;
		}

		$faq_items = Priizmo_Engine_Post_Meta::get_faq_items( $post_id );

		if ( empty( $faq_items ) ) {
			return;
		}

		$main_entity = array();

		foreach ( $faq_items as $item ) {
			if ( empty( $item['question'] ) || empty( $item['answer'] ) ) {
				continue;
			}

			$main_entity[] = array(
				'@type'          => 'Question',
				'name'           => $item['question'],
				'acceptedAnswer' => array(
					'@type' => 'Answer',
					'text'  => $item['answer'],
				),
			);
		}

		if ( empty( $main_entity ) ) {
			return;
		}

		$schema = array(
			'@context'   => 'https://schema.org',
			'@type'      => 'FAQPage',
			'mainEntity' => $main_entity,
		);

		$json = wp_json_encode( $schema, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );

		// Defensive: prevent breaking out of the <script> tag even though
		// the underlying strings are already tag-stripped plain text.
		$json = str_ireplace( '</script', '<\/script', $json );

		echo "\n<script type=\"application/ld+json\">" . $json . "</script>\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
	}
}
