<?php
if (!defined('ABSPATH')) exit;

/**
 * Schema generator — produces Schema.org JSON-LD tuned for AI answer engines.
 * Integrates with AI Schema Builder when active (it owns frontend output); otherwise
 * AIVT can output its own JSON-LD on singular pages when enabled.
 */
class AIVT_Schema {

    public static function init() {
        add_action('wp_head', [__CLASS__, 'output_head'], 7);
    }

    public static function schema_builder_active() {
        return class_exists('AISB_Schema');
    }

    /** True when any plugin (AI Schema Builder, Yoast, Rank Math) already outputs schema. */
    public static function schema_owned_externally() {
        if (class_exists('AIVT_SEO_Bridge')) {
            return AIVT_SEO_Bridge::schema_owned_externally();
        }
        return self::schema_builder_active();
    }

    /**
     * @return array|WP_Error  the JSON-LD array
     */
    public static function generate($post_id, $type = '') {
        $ctx = AIVT_API::post_context($post_id, 6000);
        if (empty($ctx)) {
            return new WP_Error('aivt_no_post', __('Post not found', 'pewit-geo-analysis-tool'));
        }
        $type = $type !== '' ? sanitize_text_field($type) : self::guess_type($post_id);
        $context = AIVT_API::context_block();

        $p  = "Generate valid Schema.org JSON-LD for this WordPress page, optimized for AI answer engines and Google rich results.\n";
        $p .= "Use @context https://schema.org and @type {$type}. Include author, datePublished, dateModified, publisher and a clear description. Add sameAs/identifier where known.\n";
        $p .= "Return ONLY a single JSON object, no markdown. Do not invent facts.\n\n";
        if ($context) {
            $p .= "Site context:\n{$context}\n\n";
        }
        $p .= "PAGE\nTitle: {$ctx['title']}\nURL: {$ctx['url']}\nAuthor: {$ctx['author']}\nSite: {$ctx['site']}\nContent:\n{$ctx['content']}\n";

        $json = AIVT_API::complete_json($p, 1400);
        if (is_wp_error($json)) {
            return $json;
        }
        if (empty($json['@context'])) {
            $json['@context'] = 'https://schema.org';
        }
        if (empty($json['@type'])) {
            $json['@type'] = $type;
        }
        AIVT_Store::save($post_id, AIVT_Store::META_SCHEMA, [
            'type' => $type,
            'json' => wp_json_encode($json, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES),
        ]);
        return $json;
    }

    public static function guess_type($post_id) {
        $pt = get_post_type($post_id);
        if ($pt === 'page') return 'WebPage';
        if ($pt === 'product' || (function_exists('wc_get_product') && get_post_type($post_id) === 'product')) return 'Product';
        return 'Article';
    }

    /** Output stored JSON-LD on singular pages, unless AI Schema Builder handles output. */
    public static function output_head() {
        if (self::schema_owned_externally()) {
            return; // avoid duplicate JSON-LD; AI Schema Builder / Yoast / Rank Math owns it
        }
        if (!is_singular()) {
            return;
        }
        $post_id = get_queried_object_id();
        $saved = AIVT_Store::get($post_id, AIVT_Store::META_SCHEMA);
        if (empty($saved['json'])) {
            return;
        }
        $decoded = json_decode($saved['json'], true);
        if (!is_array($decoded)) {
            return;
        }
        // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped -- JSON-LD encoded with JSON_HEX_TAG, so "<" and ">" become \u003C/\u003E and the value cannot break out of the <script> tag.
        echo "\n<script type=\"application/ld+json\">" . wp_json_encode($decoded, JSON_UNESCAPED_UNICODE | JSON_HEX_TAG) . "</script>\n";
    }
}
