<?php
/**
 * firefly-admin-head-schema.php
 *
 * Two responsibilities:
 *   1. Defines firefly_page_schema_build_graph() — used by functions.php
 *      to output JSON-LD into <head> for visitors.
 *   2. When included by the AJAX get_panel handler, renders the admin form.
 *
 * NEVER included directly for normal visitors.
 * All add_action / AJAX registration lives in functions.php.
 */

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

/* ============================================================
 * Type-list helpers (shared with firefly-schema.php if loaded)
 * ============================================================ */
if (!function_exists('firefly_schema_primary_choices')) {
    function firefly_schema_primary_choices(): array {
        return [
            'WebSite'       => 'WebSite (just the site)',
            'Person'        => 'Person (personal site / portfolio)',
            'Organization'  => 'Organization (company / group / non-profit)',
            'LocalBusiness' => 'LocalBusiness (shop / service / physical business)',
            'Place'         => 'Place (a location / venue / attraction)',
            'Event'         => 'Event (an event listing / gig / workshop)',
            'MusicGroup'    => 'MusicGroup (band / artist collective)',
            'CreativeWork'  => 'CreativeWork (content-focused site)',
        ];
    }
}
if (!function_exists('firefly_schema_org_subtypes')) {
    function firefly_schema_org_subtypes(): array {
        return [
            ''                        => '— None (Organization) —',
            'Corporation'             => 'Corporation',
            'EducationalOrganization' => 'EducationalOrganization',
            'NGO'                     => 'NGO',
            'GovernmentOrganization'  => 'GovernmentOrganization',
            'PerformingGroup'         => 'PerformingGroup',
            'SportsOrganization'      => 'SportsOrganization',
            'Project'                 => 'Project',
        ];
    }
}
if (!function_exists('firefly_schema_localbusiness_subtypes')) {
    function firefly_schema_localbusiness_subtypes(): array {
        return [
            ''                    => '— None (LocalBusiness) —',
            'AccountingService'   => 'AccountingService',
            'AutoDealer'          => 'AutoDealer',
            'Bakery'              => 'Bakery',
            'BarOrPub'            => 'BarOrPub',
            'CafeOrCoffeeShop'    => 'CafeOrCoffeeShop',
            'Dentist'             => 'Dentist',
            'Electrician'         => 'Electrician',
            'GeneralContractor'   => 'GeneralContractor',
            'HairSalon'           => 'HairSalon',
            'Hospital'            => 'Hospital',
            'Hotel'               => 'Hotel',
            'LegalService'        => 'LegalService',
            'MedicalBusiness'     => 'MedicalBusiness',
            'NightClub'           => 'NightClub',
            'Pharmacy'            => 'Pharmacy',
            'Physician'           => 'Physician',
            'Plumber'             => 'Plumber',
            'ProfessionalService' => 'ProfessionalService',
            'RealEstateAgent'     => 'RealEstateAgent',
            'Restaurant'          => 'Restaurant',
            'School'              => 'School',
            'Store'               => 'Store',
            'TouristAttraction'   => 'TouristAttraction',
            'TravelAgency'        => 'TravelAgency',
            'VeterinaryCare'      => 'VeterinaryCare',
        ];
    }
}
if (!function_exists('firefly_schema_creativework_subtypes')) {
    function firefly_schema_creativework_subtypes(): array {
        return [
            ''                    => '— None (CreativeWork) —',
            'Article'             => 'Article',
            'Blog'                => 'Blog',
            'BlogPosting'         => 'BlogPosting',
            'Book'                => 'Book',
            'Course'              => 'Course',
            'ImageGallery'        => 'ImageGallery',
            'MusicAlbum'          => 'MusicAlbum',
            'MusicRecording'      => 'MusicRecording',
            'PodcastSeries'       => 'PodcastSeries',
            'SoftwareApplication' => 'SoftwareApplication',
            'VideoObject'         => 'VideoObject',
        ];
    }
}
if (!function_exists('firefly_schema_place_subtypes')) {
    function firefly_schema_place_subtypes(): array {
        return [
            ''                               => '— None (Place) —',
            'CivicStructure'                 => 'CivicStructure',
            'EventVenue'                     => 'EventVenue',
            'LandmarksOrHistoricalBuildings' => 'LandmarksOrHistoricalBuildings',
            'Museum'                         => 'Museum',
            'Park'                           => 'Park',
            'StadiumOrArena'                 => 'StadiumOrArena',
            'TouristAttraction'              => 'TouristAttraction',
        ];
    }
}
if (!function_exists('firefly_schema_event_subtypes')) {
    function firefly_schema_event_subtypes(): array {
        return [
            ''               => '— None (Event) —',
            'BusinessEvent'  => 'BusinessEvent',
            'ComedyEvent'    => 'ComedyEvent',
            'DanceEvent'     => 'DanceEvent',
            'EducationEvent' => 'EducationEvent',
            'Festival'       => 'Festival',
            'FoodEvent'      => 'FoodEvent',
            'LiteraryEvent'  => 'LiteraryEvent',
            'MusicEvent'     => 'MusicEvent',
            'SalesEvent'     => 'SalesEvent',
            'ScreeningEvent' => 'ScreeningEvent',
            'SocialEvent'    => 'SocialEvent',
            'SportsEvent'    => 'SportsEvent',
            'TheaterEvent'   => 'TheaterEvent',
            'VisualArtsEvent'=> 'VisualArtsEvent',
        ];
    }
}

/* ============================================================
 * Build the JSON-LD graph array for a given post
 * Called by functions.php to inject into <head>
 * ============================================================ */
function firefly_page_schema_build_graph(int $post_id): array {
    $m = function(string $key, string $default = '') use ($post_id): string {
        return trim((string) get_post_meta($post_id, 'firefly_page_schema_' . $key, true)) ?: $default;
    };

    $primary = $m('primary_type', 'WebSite');
    $type    = $primary;

    $subtype_map = [
        'Organization'  => $m('org_subtype'),
        'LocalBusiness' => $m('localbusiness_subtype'),
        'CreativeWork'  => $m('creativework_subtype'),
        'Place'         => $m('place_subtype'),
        'Event'         => $m('event_subtype'),
    ];
    if (isset($subtype_map[$primary]) && $subtype_map[$primary] !== '') {
        $type = $subtype_map[$primary];
    }

    $page_url  = get_permalink($post_id) ?: home_url('/');
    $site_url  = home_url('/');
    $site_name = get_bloginfo('name');

    $url   = $m('url') ?: $page_url;
    $name  = $m('name') ?: get_the_title($post_id);
    $desc  = $m('description');
    $logo  = $m('logo');
    $image = $m('image');
    $phone = $m('phone');
    $email = $m('email');
    $price = $m('price_range');

    // sameAs
    $sameas = [];
    $sameas_raw = $m('sameas');
    if ($sameas_raw !== '') {
        foreach (array_filter(array_map('trim', explode("\n", str_replace("\r", "\n", $sameas_raw)))) as $line) {
            $u = esc_url_raw($line);
            if ($u) $sameas[] = $u;
        }
        $sameas = array_values(array_unique($sameas));
    }

    // Address
    $street   = $m('street');
    $locality = $m('locality');
    $region   = $m('region');
    $postcode = $m('postcode');
    $country  = $m('country');

    $address_obj = null;
    if ($street || $locality || $region || $postcode || $country) {
        $address_obj = ['@type' => 'PostalAddress'];
        if ($street)   $address_obj['streetAddress']   = $street;
        if ($locality) $address_obj['addressLocality']  = $locality;
        if ($region)   $address_obj['addressRegion']    = $region;
        if ($postcode) $address_obj['postalCode']        = $postcode;
        if ($country)  $address_obj['addressCountry']   = $country;
    }

    // Geo
    $lat = $m('lat');
    $lng = $m('lng');
    $geo_obj = null;
    if ($lat !== '' && $lng !== '') {
        $geo_obj = [
            '@type'     => 'GeoCoordinates',
            'latitude'  => (float) $lat,
            'longitude' => (float) $lng,
        ];
    }

    // Opening hours
    $oh_raw = $m('opening_hours');
    $opening_specs = function_exists('firefly_schema_parse_opening_hours')
        ? firefly_schema_parse_opening_hours($oh_raw)
        : [];

    // IDs
    $website_id = trailingslashit($site_url) . '#website';
    $entity_id  = trailingslashit($page_url) . '#entity';

    // WebSite node
    $website_node = [
        '@type' => 'WebSite',
        '@id'   => $website_id,
        'url'   => $site_url,
        'name'  => $site_name,
    ];
    if ($primary !== 'WebSite') {
        $website_node['about'] = ['@id' => $entity_id];
    }

    // Entity node
    $entity_node = [
        '@type' => $type,
        '@id'   => $entity_id,
        'name'  => $name,
        'url'   => $url,
    ];
    if ($desc  !== '') $entity_node['description'] = $desc;
    if ($logo  !== '') $entity_node['logo']         = $logo;
    if ($image !== '') $entity_node['image']        = $image;
    if ($phone !== '') $entity_node['telephone']    = $phone;
    if ($email !== '') $entity_node['email']        = $email;
    if ($price !== '') $entity_node['priceRange']   = $price;
    if (!empty($sameas))        $entity_node['sameAs']                    = $sameas;
    if ($address_obj)           $entity_node['address']                   = $address_obj;
    if ($geo_obj)               $entity_node['geo']                       = $geo_obj;
    if (!empty($opening_specs)) $entity_node['openingHoursSpecification'] = $opening_specs;

    // Event-specific fields
    if ($primary === 'Event') {
        $ev_start = $m('event_start');
        $ev_end   = $m('event_end');
        $loc_name = $m('event_location_name');
        if ($ev_start !== '') $entity_node['startDate'] = $ev_start;
        if ($ev_end   !== '') $entity_node['endDate']   = $ev_end;

        if ($address_obj || $geo_obj || $loc_name !== '') {
            $loc = ['@type' => 'Place'];
            if ($loc_name !== '') $loc['name']    = $loc_name;
            if ($address_obj)     $loc['address'] = $address_obj;
            if ($geo_obj)         $loc['geo']     = $geo_obj;
            $entity_node['location'] = $loc;
        }

        $offer_url      = $m('event_offer_url');
        $offer_price    = $m('event_offer_price');
        $offer_currency = strtoupper($m('event_offer_currency'));
        if ($offer_url !== '' || $offer_price !== '' || $offer_currency !== '') {
            $offer = ['@type' => 'Offer'];
            if ($offer_url      !== '') $offer['url']           = $offer_url;
            if ($offer_price    !== '') $offer['price']         = $offer_price;
            if ($offer_currency !== '') $offer['priceCurrency'] = $offer_currency;
            $entity_node['offers'] = $offer;
        }
    }

    return [
        '@context' => 'https://schema.org',
        '@graph'   => [$website_node, $entity_node],
    ];
}

/* ============================================================
 * GUARD — stop here if included only for function definitions.
 * functions.php defines FIREFLY_SCHEMA_LOAD_FUNCTIONS_ONLY before
 * including this file when it only needs firefly_page_schema_build_graph().
 * The admin form HTML below is never rendered for normal visitors.
 * ============================================================ */
if (defined('FIREFLY_SCHEMA_LOAD_FUNCTIONS_ONLY') && FIREFLY_SCHEMA_LOAD_FUNCTIONS_ONLY) return;

// Also stop if there is no page context at all
if (!isset($page_id) || !$page_id) {
    $page_id = (int) get_queried_object_id();
}
if (!$page_id) return;

$post = get_post($page_id);
if (!$post) return;

/* ============================================================
 * Admin panel HTML — only reached when an admin clicks "Schema"
 * ============================================================ */

// Pull existing meta
$pm = function(string $key, string $default = '') use ($page_id): string {
    $v = get_post_meta($page_id, 'firefly_page_schema_' . $key, true);
    return ($v !== '' && $v !== false && $v !== null) ? (string) $v : $default;
};

$s_enable       = (bool) get_post_meta($page_id, 'firefly_page_schema_enable', true);
$s_primary      = $pm('primary_type', 'WebSite');
$s_org_sub      = $pm('org_subtype');
$s_lb_sub       = $pm('localbusiness_subtype');
$s_cw_sub       = $pm('creativework_subtype');
$s_pl_sub       = $pm('place_subtype');
$s_ev_sub       = $pm('event_subtype');
$s_name         = $pm('name');
$s_url          = $pm('url');
$s_desc         = $pm('description');
$s_logo         = $pm('logo');
$s_image        = $pm('image');
$s_phone        = $pm('phone');
$s_email        = $pm('email');
$s_price        = $pm('price_range');
$s_sameas       = $pm('sameas');
$s_street       = $pm('street');
$s_locality     = $pm('locality');
$s_region       = $pm('region');
$s_postcode     = $pm('postcode');
$s_country      = $pm('country');
$s_lat          = $pm('lat');
$s_lng          = $pm('lng');
$s_hours        = $pm('opening_hours');
$s_ev_start     = $pm('event_start');
$s_ev_end       = $pm('event_end');
$s_ev_loc       = $pm('event_location_name');
$s_ev_tix_url   = $pm('event_offer_url');
$s_ev_tix_price = $pm('event_offer_price');
$s_ev_tix_curr  = $pm('event_offer_currency');

// Select builder
$sel = function(array $choices, string $current): string {
    $out = '';
    foreach ($choices as $val => $label) {
        $out .= '<option value="' . esc_attr($val) . '"' . selected($current, $val, false) . '>'
              . esc_html($label) . '</option>';
    }
    return $out;
};

// Unique prefix for this page
$uid        = 'ffpschema_' . $page_id;
$save_nonce = wp_create_nonce('firefly_page_schema_save');
$ajax_url   = admin_url('admin-ajax.php');

// Current JSON preview
$current_graph   = firefly_page_schema_build_graph($page_id);
$current_preview = wp_json_encode($current_graph, JSON_UNESCAPED_SLASHES | JSON_UNESCAPED_UNICODE | JSON_PRETTY_PRINT);

$do_highlight = function_exists('firefly_schema_syntax_highlight')
    ? 'firefly_schema_syntax_highlight'
    : function(string $json): string { return htmlspecialchars($json, ENT_QUOTES, 'UTF-8'); };

// Shared style strings
$inp  = ' style="width:100%; padding:5px 7px; border:1px solid #ccc; border-radius:4px; font-size:13px;"';
$tinp = ' style="width:100%; padding:5px 7px; border:1px solid #ccc; border-radius:4px; font-size:13px; min-height:60px;"';

// Helper closures
$section = function(string $title, string $desc = '') {
    echo '<div style="font-weight:900; font-size:14px; margin:18px 0 6px 0; color:#333;">' . esc_html($title) . '</div>';
    if ($desc !== '') {
        echo '<div style="color:#888; font-size:12px; margin-bottom:8px;">' . esc_html($desc) . '</div>';
    }
};

$field = function(string $label, string $input, string $desc = '') {
    echo '<div style="margin-bottom:12px;">';
    echo '<label style="font-weight:600; display:block; margin-bottom:4px;">' . esc_html($label) . '</label>';
    echo $input;
    if ($desc !== '') {
        echo '<div style="color:#888; font-size:11px; margin-top:3px;">' . esc_html($desc) . '</div>';
    }
    echo '</div>';
};
?>

<div id="<?php echo esc_attr($uid . '_panel'); ?>" style="margin-top:10px; padding:18px; background:#fff; color:#111; border:1px solid #ddd; border-radius:12px; font-family:Arial,sans-serif;">

    <div style="display:flex; align-items:flex-start; justify-content:space-between; gap:12px; flex-wrap:wrap;">
        <div>
            <div style="font-size:18px; font-weight:900; margin-bottom:4px;">Page Schema</div>
            <div style="color:#666; font-size:13px;"><?php echo esc_html(get_the_title($page_id)); ?></div>
        </div>
        <div style="display:flex; gap:10px; align-items:center; flex-wrap:wrap;">
            <?php if ($s_enable): ?>
                <div style="padding:6px 12px; border-radius:999px; border:1px solid rgba(10,107,43,.25); background:rgba(10,107,43,.06); color:#0a6b2b; font-weight:900;">Active</div>
            <?php else: ?>
                <div style="padding:6px 12px; border-radius:999px; border:1px solid #ddd; background:#f9f9f9; color:#888; font-weight:900;">Inactive</div>
            <?php endif; ?>
        </div>
    </div>

    <hr style="border:none; border-top:1px solid #eee; margin:16px 0;">

    <?php if (!$s_enable): ?>
        <div style="margin-bottom:14px; background:#fff3cd; color:#856404; padding:10px 14px; border-radius:8px; border:1px solid #ffc107; font-weight:700;">
            Page schema is not enabled. Enable it below to inject schema into this page's &lt;head&gt;.
        </div>
    <?php endif; ?>

    <form id="<?php echo esc_attr($uid . '_form'); ?>">
        <input type="hidden" name="action"  value="firefly_page_schema_save">
        <input type="hidden" name="nonce"   value="<?php echo esc_attr($save_nonce); ?>">
        <input type="hidden" name="page_id" value="<?php echo (int) $page_id; ?>">

        <?php $section('Enable'); ?>
        <div style="margin-bottom:14px;">
            <label style="font-weight:600; display:flex; align-items:center; gap:8px; cursor:pointer;">
                <input type="checkbox" name="firefly_page_schema_enable" value="1"
                    id="<?php echo esc_attr($uid . '_enable'); ?>"
                    <?php checked($s_enable); ?>>
                Enable schema for this page
            </label>
            <div style="color:#888; font-size:11px; margin-top:4px;">
                Injects a JSON-LD &lt;script&gt; into this page's &lt;head&gt;, separate from the site-wide schema.
            </div>
        </div>

        <?php $section('Schema Type'); ?>

        <?php $field('Primary type',
            '<select name="firefly_page_schema_primary_type" id="' . esc_attr($uid . '_ptype') . '"' . $inp . '>'
            . $sel(firefly_schema_primary_choices(), $s_primary)
            . '</select>'
        ); ?>

        <div class="<?php echo esc_attr($uid); ?>-sub" data-for="Organization" style="margin-bottom:12px;<?php echo $s_primary !== 'Organization' ? ' display:none;' : ''; ?>">
            <label style="font-weight:600; display:block; margin-bottom:4px;">Organization subtype (optional)</label>
            <select name="firefly_page_schema_org_subtype"<?php echo $inp; ?>><?php echo $sel(firefly_schema_org_subtypes(), $s_org_sub); ?></select>
        </div>
        <div class="<?php echo esc_attr($uid); ?>-sub" data-for="LocalBusiness" style="margin-bottom:12px;<?php echo $s_primary !== 'LocalBusiness' ? ' display:none;' : ''; ?>">
            <label style="font-weight:600; display:block; margin-bottom:4px;">LocalBusiness subtype (optional)</label>
            <select name="firefly_page_schema_localbusiness_subtype"<?php echo $inp; ?>><?php echo $sel(firefly_schema_localbusiness_subtypes(), $s_lb_sub); ?></select>
        </div>
        <div class="<?php echo esc_attr($uid); ?>-sub" data-for="CreativeWork" style="margin-bottom:12px;<?php echo $s_primary !== 'CreativeWork' ? ' display:none;' : ''; ?>">
            <label style="font-weight:600; display:block; margin-bottom:4px;">CreativeWork subtype (optional)</label>
            <select name="firefly_page_schema_creativework_subtype"<?php echo $inp; ?>><?php echo $sel(firefly_schema_creativework_subtypes(), $s_cw_sub); ?></select>
        </div>
        <div class="<?php echo esc_attr($uid); ?>-sub" data-for="Place" style="margin-bottom:12px;<?php echo $s_primary !== 'Place' ? ' display:none;' : ''; ?>">
            <label style="font-weight:600; display:block; margin-bottom:4px;">Place subtype (optional)</label>
            <select name="firefly_page_schema_place_subtype"<?php echo $inp; ?>><?php echo $sel(firefly_schema_place_subtypes(), $s_pl_sub); ?></select>
        </div>
        <div class="<?php echo esc_attr($uid); ?>-sub" data-for="Event" style="margin-bottom:12px;<?php echo $s_primary !== 'Event' ? ' display:none;' : ''; ?>">
            <label style="font-weight:600; display:block; margin-bottom:4px;">Event subtype (optional)</label>
            <select name="firefly_page_schema_event_subtype"<?php echo $inp; ?>><?php echo $sel(firefly_schema_event_subtypes(), $s_ev_sub); ?></select>
        </div>

        <?php $section('Core Details'); ?>
        <?php
        $field('Name',        '<input type="text" name="firefly_page_schema_name"  value="' . esc_attr($s_name)  . '" placeholder="' . esc_attr(get_the_title($page_id)) . '"' . $inp . '>', 'Defaults to the page title if left blank.');
        $field('URL',         '<input type="text" name="firefly_page_schema_url"   value="' . esc_attr($s_url)   . '" placeholder="' . esc_attr(get_permalink($page_id) ?: '') . '"' . $inp . '>', 'Defaults to this page\'s permalink if left blank.');
        $field('Description', '<textarea name="firefly_page_schema_description"' . $tinp . '>' . esc_textarea($s_desc) . '</textarea>');
        $field('Logo URL',    '<input type="text" name="firefly_page_schema_logo"  value="' . esc_attr($s_logo)  . '"' . $inp . '>', 'Direct image URL.');
        $field('Image URL',   '<input type="text" name="firefly_page_schema_image" value="' . esc_attr($s_image) . '"' . $inp . '>', 'Direct image URL.');
        $field('Telephone',   '<input type="text" name="firefly_page_schema_phone" value="' . esc_attr($s_phone) . '"' . $inp . '>');
        $field('Email',       '<input type="text" name="firefly_page_schema_email" value="' . esc_attr($s_email) . '"' . $inp . '>');
        $field('Price Range', '<input type="text" name="firefly_page_schema_price_range" value="' . esc_attr($s_price) . '"' . $inp . '>', 'Example: $$ or $10–$50');
        $field('sameAs / Social Links', '<textarea name="firefly_page_schema_sameas" rows="3"' . $tinp . '>' . esc_textarea($s_sameas) . '</textarea>', 'One URL per line.');
        ?>

        <?php $section('Address & Location', 'Used for LocalBusiness, Place, and Event location.'); ?>
        <?php
        $field('Street Address', '<input type="text" name="firefly_page_schema_street"   value="' . esc_attr($s_street)   . '"' . $inp . '>');
        $field('City / Locality','<input type="text" name="firefly_page_schema_locality" value="' . esc_attr($s_locality) . '"' . $inp . '>');
        $field('Region / State', '<input type="text" name="firefly_page_schema_region"   value="' . esc_attr($s_region)   . '"' . $inp . '>');
        $field('Postal Code',    '<input type="text" name="firefly_page_schema_postcode" value="' . esc_attr($s_postcode) . '"' . $inp . '>');
        $field('Country',        '<input type="text" name="firefly_page_schema_country"  value="' . esc_attr($s_country)  . '"' . $inp . '>', 'Example: NZ, US, AU, VN');
        $field('Latitude',       '<input type="text" name="firefly_page_schema_lat"      value="' . esc_attr($s_lat)      . '"' . $inp . '>');
        $field('Longitude',      '<input type="text" name="firefly_page_schema_lng"      value="' . esc_attr($s_lng)      . '"' . $inp . '>');
        $field('Opening Hours',  '<textarea name="firefly_page_schema_opening_hours" rows="4"' . $tinp . '>' . esc_textarea($s_hours) . '</textarea>', 'One per line e.g. Mo-Fr 09:00-17:00 · Sa 10:00-14:00 · Su closed');
        ?>

        <div id="<?php echo esc_attr($uid . '_eventblock'); ?>" style="<?php echo $s_primary !== 'Event' ? 'display:none;' : ''; ?>">
            <?php $section('Event Details', 'Only used when primary type is Event.'); ?>
            <?php
            $field('Start DateTime',     '<input type="text" name="firefly_page_schema_event_start"            value="' . esc_attr($s_ev_start)     . '"' . $inp . '>', 'ISO format e.g. 2026-03-10T19:30');
            $field('End DateTime',       '<input type="text" name="firefly_page_schema_event_end"              value="' . esc_attr($s_ev_end)       . '"' . $inp . '>', 'ISO format e.g. 2026-03-10T22:00');
            $field('Venue Name',         '<input type="text" name="firefly_page_schema_event_location_name"    value="' . esc_attr($s_ev_loc)       . '"' . $inp . '>', 'Address/geo comes from the fields above.');
            $field('Ticket / Offer URL', '<input type="text" name="firefly_page_schema_event_offer_url"        value="' . esc_attr($s_ev_tix_url)   . '"' . $inp . '>');
            $field('Ticket Price',       '<input type="text" name="firefly_page_schema_event_offer_price"      value="' . esc_attr($s_ev_tix_price) . '"' . $inp . '>', 'Example: 20 or 20.00');
            $field('Ticket Currency',    '<input type="text" name="firefly_page_schema_event_offer_currency"   value="' . esc_attr($s_ev_tix_curr)  . '"' . $inp . '>', 'Example: NZD, USD, VND');
            ?>
        </div>

        <div style="margin-top:18px; display:flex; align-items:center; gap:10px; flex-wrap:wrap;">
            <button type="submit" class="button button-primary" id="<?php echo esc_attr($uid . '_save'); ?>">Save schema</button>
            <span id="<?php echo esc_attr($uid . '_msg'); ?>" style="color:#0a6b2b; font-weight:700; display:none;">Saved ✓</span>
            <span id="<?php echo esc_attr($uid . '_err'); ?>" style="color:#b00020; font-weight:700; display:none;">Save failed</span>
        </div>
    </form>

    <hr style="border:none; border-top:1px solid #eee; margin:18px 0;">

    <div style="margin-bottom:8px; display:flex; align-items:center; gap:10px; flex-wrap:wrap;">
        <div style="font-weight:900;">JSON-LD Preview</div>
        <button type="button" id="<?php echo esc_attr($uid . '_preview_toggle'); ?>"
            style="background:none; border:1px solid #ccc; border-radius:4px; padding:3px 10px; font-size:12px; cursor:pointer;">
            Show JSON
        </button>
    </div>
    <div id="<?php echo esc_attr($uid . '_preview_wrap'); ?>" style="display:none;">
        <pre id="<?php echo esc_attr($uid . '_preview'); ?>"
            style="background:#0f0f10; color:#d4d4d4; padding:16px; border-radius:10px; font-size:12px; line-height:1.55; overflow:auto; max-height:420px; white-space:pre;"><?php
            echo $do_highlight($current_preview);
        ?></pre>
    </div>

</div><!-- end panel -->

<script id="ffpschema-boot-<?php echo (int) $page_id; ?>">
(function () {
    var uid     = <?php echo json_encode($uid); ?>;
    var ajaxUrl = <?php echo json_encode($ajax_url); ?>;
    var form    = document.getElementById(uid + '_form');
    if (!form) return;

    // Subtype visibility
    var ptypeEl    = document.getElementById(uid + '_ptype');
    var eventBlock = document.getElementById(uid + '_eventblock');
    var subDivs    = document.querySelectorAll('.' + uid + '-sub');

    function showSubtype() {
        if (!ptypeEl) return;
        var val = ptypeEl.value;
        subDivs.forEach(function (d) {
            d.style.display = (d.getAttribute('data-for') === val) ? '' : 'none';
        });
        if (eventBlock) eventBlock.style.display = (val === 'Event') ? '' : 'none';
    }
    if (ptypeEl) ptypeEl.addEventListener('change', showSubtype);
    showSubtype();

    // JSON preview toggle
    var previewToggle = document.getElementById(uid + '_preview_toggle');
    var previewWrap   = document.getElementById(uid + '_preview_wrap');
    if (previewToggle && previewWrap) {
        previewToggle.addEventListener('click', function () {
            var open = previewWrap.style.display !== 'none';
            previewWrap.style.display = open ? 'none' : 'block';
            previewToggle.textContent = open ? 'Show JSON' : 'Hide JSON';
        });
    }

    // Form save
    form.addEventListener('submit', function (e) {
        e.preventDefault();
        var saveBtn = document.getElementById(uid + '_save');
        var msgEl   = document.getElementById(uid + '_msg');
        var errEl   = document.getElementById(uid + '_err');
        if (saveBtn) saveBtn.disabled = true;
        if (msgEl)   msgEl.style.display = 'none';
        if (errEl)   errEl.style.display = 'none';

        var fd = new FormData(form);
        // Ensure checkbox value is always sent
        if (!fd.has('firefly_page_schema_enable')) {
            fd.set('firefly_page_schema_enable', '');
        }

        fetch(ajaxUrl, { method: 'POST', credentials: 'same-origin', body: fd })
            .then(function (r) { return r.json(); })
            .then(function (res) {
                if (saveBtn) saveBtn.disabled = false;
                if (res && res.success) {
                    if (msgEl) {
                        msgEl.style.display = 'inline';
                        setTimeout(function () { msgEl.style.display = 'none'; }, 3000);
                    }
                } else {
                    if (errEl) errEl.style.display = 'inline';
                }
            })
            .catch(function () {
                if (saveBtn) saveBtn.disabled = false;
                if (errEl)   errEl.style.display = 'inline';
            });
    });

})();
</script>
