<?php
/**
 * Schema Injector.
 *
 * Emits HowTo + FAQPage JSON-LD into <head> on single posts, built from the
 * per-post fields saved in the editor panel. No third-party plugin, no code
 * edits per article — the editor fills in fields, this turns them into valid
 * structured data.
 *
 * @package Platform\Helm\Modules\Schema
 */

declare( strict_types = 1 );

namespace Platform\Helm\Modules\Schema;

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

final class SchemaInjector {

	public const META_HOWTO = '_platform_helm_schema_howto';
	public const META_FAQ   = '_platform_helm_schema_faq';

	public function register_hooks(): void {
		add_action( 'wp_head', [ $this, 'inject' ], 5 );
	}

	public function inject(): void {
		if ( ! is_singular( \Platform\Helm\Core\PostTypes::content() ) ) {
			return;
		}
		$post_id = (int) get_queried_object_id();
		$url     = (string) get_permalink( $post_id );

		$howto = get_post_meta( $post_id, self::META_HOWTO, true );
		$faq   = get_post_meta( $post_id, self::META_FAQ, true );

		if ( is_array( $howto ) && ! empty( $howto['steps'] ) ) {
			$this->print_jsonld( $this->build_howto( $howto, $url ) );
		}
		if ( is_array( $faq ) && ! empty( $faq ) ) {
			$this->print_jsonld( $this->build_faq( $faq ) );
		}
	}

	/**
	 * @param array<string,mixed> $h
	 * @return array<string,mixed>
	 */
	private function build_howto( array $h, string $url ): array {
		$data = [
			'@context' => 'https://schema.org',
			'@type'    => 'HowTo',
			'name'     => (string) ( $h['name'] ?? get_the_title() ),
		];
		if ( ! empty( $h['description'] ) ) {
			$data['description'] = (string) $h['description'];
		}
		if ( ! empty( $h['total_time'] ) ) {
			$data['totalTime'] = (string) $h['total_time'];
		}
		if ( ! empty( $h['cost'] ) ) {
			$data['estimatedCost'] = [
				'@type'    => 'MonetaryAmount',
				'currency' => 'ZAR',
				'value'    => (string) $h['cost'],
			];
		}
		$steps = [];
		$i     = 0;
		foreach ( (array) $h['steps'] as $step ) {
			$name = (string) ( $step['name'] ?? '' );
			$text = (string) ( $step['text'] ?? '' );
			if ( '' === $name && '' === $text ) {
				continue;
			}
			$i++;
			$steps[] = [
				'@type'    => 'HowToStep',
				'position' => (string) $i,
				'name'     => $name,
				'text'     => $text,
				'url'      => $url . '#step' . $i,
			];
		}
		$data['step'] = $steps;
		return $data;
	}

	/**
	 * @param array<int,array<string,string>> $faq
	 * @return array<string,mixed>
	 */
	private function build_faq( array $faq ): array {
		$entities = [];
		foreach ( $faq as $item ) {
			$q = (string) ( $item['q'] ?? '' );
			$a = (string) ( $item['a'] ?? '' );
			if ( '' === $q || '' === $a ) {
				continue;
			}
			$entities[] = [
				'@type'          => 'Question',
				'name'           => $q,
				'acceptedAnswer' => [ '@type' => 'Answer', 'text' => $a ],
			];
		}
		return [
			'@context'   => 'https://schema.org',
			'@type'      => 'FAQPage',
			'mainEntity' => $entities,
		];
	}

	/**
	 * @param array<string,mixed> $data
	 */
	private function print_jsonld( array $data ): void {
		$json = wp_json_encode( $data, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE );
		if ( false === $json ) {
			return;
		}
		// Neutralise any stray tag characters so we can't break out of <script>.
		$json = str_replace( [ '<', '>' ], [ '\u003C', '\u003E' ], $json );
		echo "\n" . '<script type="application/ld+json">' . $json . '</script>' . "\n"; // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
	}
}
