<?php
/**
 * Schema Meta Box.
 *
 * Editor panel on posts for HowTo + FAQ structured data. The editor fills in
 * fields; SchemaInjector turns them into JSON-LD. No code per article.
 *
 * @package Platform\Helm\Modules\Schema
 */

declare( strict_types = 1 );

namespace Platform\Helm\Modules\Schema;

use Platform\Helm\Core\Assets;
use Platform\Helm\Core\Authorization;
use Platform\Helm\Core\LlmClient;
use Platform\Helm\Core\LlmSettings;
use Platform\Helm\Core\PostTypes;

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

final class SchemaMetaBox {

	private const NONCE          = 'platform_helm_schema_meta';
	private const GENERATE_NONCE = 'platform_helm_schema_generate';

	public function __construct( private Assets $assets ) {}

	public function register_hooks(): void {
		add_action( 'add_meta_boxes', [ $this, 'add' ] );
		add_action( 'save_post', [ $this, 'save' ], 10, 2 );
		add_action( 'admin_enqueue_scripts', [ $this, 'enqueue' ] );
		add_action( 'wp_ajax_platform_helm_schema_generate', [ $this, 'ajax_generate' ] );
	}

	public function enqueue( string $hook ): void {
		if ( 'post.php' !== $hook && 'post-new.php' !== $hook ) {
			return;
		}
		$screen = get_current_screen();
		if ( ! $screen || ! in_array( $screen->post_type, PostTypes::content(), true ) ) {
			return;
		}
		$this->assets->enqueue_schema_metabox();
		wp_localize_script( 'platform-helm-schema', 'PlatformHelmSchema', [
			'ajaxUrl'    => admin_url( 'admin-ajax.php' ),
			'nonce'      => wp_create_nonce( self::GENERATE_NONCE ),
			'action'     => 'platform_helm_schema_generate',
			'configured' => LlmSettings::is_configured() ? '1' : '',
		] );
	}

	public function add(): void {
		add_meta_box(
			'platform-helm-schema',
			__( "Helm — Structured Data (Schema)", 'platform-helm' ),
			[ $this, 'render' ],
			PostTypes::content(),
			'normal',
			'default'
		);
	}

	public function render( \WP_Post $post ): void {
		wp_nonce_field( self::NONCE, self::NONCE );
		$howto = get_post_meta( $post->ID, SchemaInjector::META_HOWTO, true );
		$faq   = get_post_meta( $post->ID, SchemaInjector::META_FAQ, true );
		$howto = is_array( $howto ) ? $howto : [];
		$faq   = is_array( $faq ) ? $faq : [];
		$steps = $howto['steps'] ?? [];
		?>
		<div class="ph-schema">
			<p class="ph-schema-help"><?php esc_html_e( 'Fill in only what applies. HowTo schema is emitted if there is at least one step; FAQ schema if there is at least one question. Leave everything blank to emit nothing.', 'platform-helm' ); ?></p>

			<?php if ( LlmSettings::is_configured() ) : ?>
				<p>
					<button type="button" class="button button-primary" id="ph-schema-generate"><?php esc_html_e( 'Generate from content (AI)', 'platform-helm' ); ?></button>
					<span id="ph-schema-gen-msg" class="ph-schema-help" aria-live="polite"></span>
				</p>
				<p class="ph-schema-help"><?php esc_html_e( 'Reads this article and drafts FAQ/HowTo from what is actually written. Review and edit before saving — it can miss or misread; nothing is saved until you update the post.', 'platform-helm' ); ?></p>
			<?php endif; ?>

			<h4 class="ph-schema-h"><?php esc_html_e( 'HowTo', 'platform-helm' ); ?></h4>
			<p><label><?php esc_html_e( 'Name', 'platform-helm' ); ?><br />
				<input type="text" name="topla_howto_name" class="widefat" value="<?php echo esc_attr( (string) ( $howto['name'] ?? '' ) ); ?>" placeholder="<?php esc_attr_e( 'How to Do Something, Step by Step', 'platform-helm' ); ?>" /></label></p>
			<p><label><?php esc_html_e( 'Description', 'platform-helm' ); ?><br />
				<textarea name="topla_howto_description" class="widefat" rows="2"><?php echo esc_textarea( (string) ( $howto['description'] ?? '' ) ); ?></textarea></label></p>
			<p style="display:flex; gap:14px; flex-wrap:wrap;">
				<label><?php esc_html_e( 'Total time (ISO 8601, e.g. PT3D)', 'platform-helm' ); ?><br />
					<input type="text" name="topla_howto_total_time" value="<?php echo esc_attr( (string) ( $howto['total_time'] ?? '' ) ); ?>" placeholder="PT3D" /></label>
				<label><?php esc_html_e( 'Estimated cost (ZAR)', 'platform-helm' ); ?><br />
					<input type="text" name="topla_howto_cost" value="<?php echo esc_attr( (string) ( $howto['cost'] ?? '' ) ); ?>" placeholder="175" /></label>
			</p>

			<div class="ph-schema-rows" id="ph-howto-steps">
				<?php
				if ( empty( $steps ) ) {
					$steps = [ [ 'name' => '', 'text' => '' ] ];
				}
				foreach ( $steps as $s ) :
					?>
					<div class="ph-schema-row">
						<input type="text" name="topla_howto_step_name[]" class="widefat" value="<?php echo esc_attr( (string) ( $s['name'] ?? '' ) ); ?>" placeholder="<?php esc_attr_e( 'Step name', 'platform-helm' ); ?>" />
						<textarea name="topla_howto_step_text[]" class="widefat" rows="2" placeholder="<?php esc_attr_e( 'Step instructions', 'platform-helm' ); ?>"><?php echo esc_textarea( (string) ( $s['text'] ?? '' ) ); ?></textarea>
						<button type="button" class="button-link ph-schema-remove" aria-label="<?php esc_attr_e( 'Remove', 'platform-helm' ); ?>">✕</button>
					</div>
				<?php endforeach; ?>
			</div>
			<p><button type="button" class="button" id="ph-add-step"><?php esc_html_e( '+ Add step', 'platform-helm' ); ?></button></p>

			<h4 class="ph-schema-h"><?php esc_html_e( 'FAQ', 'platform-helm' ); ?></h4>
			<div class="ph-schema-rows" id="ph-faq-rows">
				<?php
				if ( empty( $faq ) ) {
					$faq = [ [ 'q' => '', 'a' => '' ] ];
				}
				foreach ( $faq as $f ) :
					?>
					<div class="ph-schema-row">
						<input type="text" name="topla_faq_q[]" class="widefat" value="<?php echo esc_attr( (string) ( $f['q'] ?? '' ) ); ?>" placeholder="<?php esc_attr_e( 'Question', 'platform-helm' ); ?>" />
						<textarea name="topla_faq_a[]" class="widefat" rows="2" placeholder="<?php esc_attr_e( 'Answer', 'platform-helm' ); ?>"><?php echo esc_textarea( (string) ( $f['a'] ?? '' ) ); ?></textarea>
						<button type="button" class="button-link ph-schema-remove" aria-label="<?php esc_attr_e( 'Remove', 'platform-helm' ); ?>">✕</button>
					</div>
				<?php endforeach; ?>
			</div>
			<p><button type="button" class="button" id="ph-add-faq"><?php esc_html_e( '+ Add FAQ', 'platform-helm' ); ?></button></p>

			<template id="ph-step-tpl">
				<div class="ph-schema-row">
					<input type="text" name="topla_howto_step_name[]" class="widefat" placeholder="<?php esc_attr_e( 'Step name', 'platform-helm' ); ?>" />
					<textarea name="topla_howto_step_text[]" class="widefat" rows="2" placeholder="<?php esc_attr_e( 'Step instructions', 'platform-helm' ); ?>"></textarea>
					<button type="button" class="button-link ph-schema-remove" aria-label="<?php esc_attr_e( 'Remove', 'platform-helm' ); ?>">✕</button>
				</div>
			</template>
			<template id="ph-faq-tpl">
				<div class="ph-schema-row">
					<input type="text" name="topla_faq_q[]" class="widefat" placeholder="<?php esc_attr_e( 'Question', 'platform-helm' ); ?>" />
					<textarea name="topla_faq_a[]" class="widefat" rows="2" placeholder="<?php esc_attr_e( 'Answer', 'platform-helm' ); ?>"></textarea>
					<button type="button" class="button-link ph-schema-remove" aria-label="<?php esc_attr_e( 'Remove', 'platform-helm' ); ?>">✕</button>
				</div>
			</template>
		</div>
		<?php
	}

	/**
	 * AI Auto-Schema: read the article and draft FAQ/HowTo as JSON for review.
	 * Strictly grounded in the article text; nothing is persisted here.
	 */
	public function ajax_generate(): void {
		check_ajax_referer( self::GENERATE_NONCE, 'nonce' );
		Authorization::require_master_admin_ajax();

		$post_id = isset( $_POST['post_id'] ) ? (int) $_POST['post_id'] : 0;
		$post    = $post_id > 0 ? get_post( $post_id ) : null;
		if ( ! $post ) {
			wp_send_json_error( [ 'message' => __( 'Post not found.', 'platform-helm' ) ] );
		}

		$title   = get_the_title( $post );
		$content = wp_strip_all_tags( strip_shortcodes( (string) $post->post_content ) );
		$content = mb_substr( trim( (string) preg_replace( '/\s+/', ' ', $content ) ), 0, 12000 );
		if ( '' === trim( $content ) ) {
			wp_send_json_error( [ 'message' => __( 'This post has no readable content yet. Add and save content first.', 'platform-helm' ) ] );
		}

		$system = 'You extract structured data from an article. '
			. 'From ONLY the article text, identify any genuine FAQ (question/answer) pairs and any genuine step-by-step HowTo. '
			. 'Never invent steps, answers or facts that the text does not support. If there is no how-to, return an empty steps array; if no FAQ, return an empty faq array. '
			. 'Keep each answer and step concise (1–3 sentences), paraphrased from the article, in clear plain English. '
			. 'Return ONLY minified JSON — no markdown, no code fences, no commentary — exactly in this shape: '
			. '{"howto":{"name":"","description":"","steps":[{"name":"","text":""}]},"faq":[{"q":"","a":""}]}';
		$user = 'Title: ' . $title . "\n\nArticle:\n" . $content;

		$res = LlmClient::chat(
			[
				[ 'role' => 'system', 'content' => $system ],
				[ 'role' => 'user', 'content' => $user ],
			],
			[ 'max_tokens' => 1200, 'temperature' => 0.2 ]
		);
		if ( is_wp_error( $res ) ) {
			wp_send_json_error( [ 'message' => $res->get_error_message() ] );
		}

		$data = json_decode( $this->extract_json( $res ), true );
		if ( ! is_array( $data ) ) {
			wp_send_json_error( [ 'message' => __( 'Could not parse the AI response. Try again.', 'platform-helm' ) ] );
		}

		$howto    = is_array( $data['howto'] ?? null ) ? $data['howto'] : [];
		$steps_in = is_array( $howto['steps'] ?? null ) ? $howto['steps'] : [];
		$steps    = [];
		foreach ( $steps_in as $s ) {
			if ( ! is_array( $s ) ) {
				continue;
			}
			$n = sanitize_text_field( (string) ( $s['name'] ?? '' ) );
			$t = sanitize_textarea_field( (string) ( $s['text'] ?? '' ) );
			if ( '' !== $n || '' !== $t ) {
				$steps[] = [ 'name' => $n, 'text' => $t ];
			}
		}

		$faq_in = is_array( $data['faq'] ?? null ) ? $data['faq'] : [];
		$faq    = [];
		foreach ( $faq_in as $f ) {
			if ( ! is_array( $f ) ) {
				continue;
			}
			$q = sanitize_text_field( (string) ( $f['q'] ?? '' ) );
			$a = sanitize_textarea_field( (string) ( $f['a'] ?? '' ) );
			if ( '' !== $q && '' !== $a ) {
				$faq[] = [ 'q' => $q, 'a' => $a ];
			}
		}

		wp_send_json_success( [
			'howto' => [
				'name'        => sanitize_text_field( (string) ( $howto['name'] ?? '' ) ),
				'description' => sanitize_textarea_field( (string) ( $howto['description'] ?? '' ) ),
				'steps'       => $steps,
			],
			'faq'   => $faq,
		] );
	}

	/** Pull the outermost JSON object out of a model response (strips fences/prose). */
	private function extract_json( string $s ): string {
		$s     = (string) preg_replace( '/^```(?:json)?\s*/i', '', trim( $s ) );
		$s     = (string) preg_replace( '/\s*```$/', '', $s );
		$start = strpos( $s, '{' );
		$end   = strrpos( $s, '}' );
		if ( false !== $start && false !== $end && $end > $start ) {
			return substr( $s, $start, $end - $start + 1 );
		}
		return $s;
	}

	public function save( int $post_id, \WP_Post $post ): void {
		if ( ! in_array( $post->post_type, PostTypes::content(), true ) ) {
			return;
		}
		if ( ! isset( $_POST[ self::NONCE ] ) || ! wp_verify_nonce( sanitize_text_field( wp_unslash( $_POST[ self::NONCE ] ) ), self::NONCE ) ) {
			return;
		}
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return;
		}
		if ( ! current_user_can( 'edit_post', $post_id ) ) {
			return;
		}

		// HowTo.
		$names = isset( $_POST['topla_howto_step_name'] ) ? (array) wp_unslash( $_POST['topla_howto_step_name'] ) : []; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
		$texts = isset( $_POST['topla_howto_step_text'] ) ? (array) wp_unslash( $_POST['topla_howto_step_text'] ) : []; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
		$steps = [];
		foreach ( $names as $i => $n ) {
			$n = sanitize_text_field( (string) $n );
			$t = sanitize_textarea_field( (string) ( $texts[ $i ] ?? '' ) );
			if ( '' !== $n || '' !== $t ) {
				$steps[] = [ 'name' => $n, 'text' => $t ];
			}
		}
		$howto = [
			'name'        => sanitize_text_field( wp_unslash( $_POST['topla_howto_name'] ?? '' ) ),
			'description' => sanitize_textarea_field( wp_unslash( $_POST['topla_howto_description'] ?? '' ) ),
			'total_time'  => sanitize_text_field( wp_unslash( $_POST['topla_howto_total_time'] ?? '' ) ),
			'cost'        => preg_replace( '/[^0-9.]/', '', (string) wp_unslash( $_POST['topla_howto_cost'] ?? '' ) ),
			'steps'       => $steps,
		];
		if ( empty( $steps ) ) {
			delete_post_meta( $post_id, SchemaInjector::META_HOWTO );
		} else {
			update_post_meta( $post_id, SchemaInjector::META_HOWTO, $howto );
		}

		// FAQ.
		$qs  = isset( $_POST['topla_faq_q'] ) ? (array) wp_unslash( $_POST['topla_faq_q'] ) : []; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
		$as  = isset( $_POST['topla_faq_a'] ) ? (array) wp_unslash( $_POST['topla_faq_a'] ) : []; // phpcs:ignore WordPress.Security.ValidatedSanitizedInput
		$faq = [];
		foreach ( $qs as $i => $q ) {
			$q = sanitize_text_field( (string) $q );
			$a = sanitize_textarea_field( (string) ( $as[ $i ] ?? '' ) );
			if ( '' !== $q && '' !== $a ) {
				$faq[] = [ 'q' => $q, 'a' => $a ];
			}
		}
		if ( empty( $faq ) ) {
			delete_post_meta( $post_id, SchemaInjector::META_FAQ );
		} else {
			update_post_meta( $post_id, SchemaInjector::META_FAQ, $faq );
		}
	}
}
