<?php
/**
 * Extensions REST API Controller.
 *
 * Manages TitanCart's built-in extension registry: list, toggle status,
 * fetch/save per-extension settings.
 *
 * Endpoints (all require manage_options):
 *
 *   GET  /titancart/v1/extensions                    List all extensions + status
 *   PUT  /titancart/v1/extensions/(?P<id>[\w-]+)     Toggle extension status
 *   GET  /titancart/v1/extensions/(?P<id>[\w-]+)/settings   Get extension settings
 *   PUT  /titancart/v1/extensions/(?P<id>[\w-]+)/settings   Save extension settings
 *
 * @package TitanCart\REST\Extensions
 */

namespace TitanCart\REST\Extensions;

use WP_REST_Controller;
use WP_REST_Server;
use WP_REST_Request;
use WP_REST_Response;
use WP_Error;

defined( 'ABSPATH' ) || exit;

class ExtensionsController extends WP_REST_Controller {

    protected $namespace = 'titancart/v1';
    protected $rest_base = 'extensions';

    /* ══════════════════════════════════════════════════════════════════════
     * BUILT-IN EXTENSION DEFINITIONS
     * ══════════════════════════════════════════════════════════════════════ */

    private static function definitions(): array {
        return [
            'bestsellers' => [
                'name'    => 'Best Sellers',
                'desc'    => 'Collects best-selling and on-sale product data. Adds "Best Sellers" and "On Sale" blocks to your storefront.',
                'version' => '1.0.0',
                'default' => 'active',
            ],
            'reviews' => [
                'name'    => 'Customer Product Reviews',
                'desc'    => 'Let customers leave product reviews with star ratings, moderation queue, and helpful votes.',
                'version' => '1.0.0',
                'default' => 'active',
            ],
            'gdpr' => [
                'name'    => 'GDPR Compliance',
                'desc'    => 'Helps comply with GDPR by showing cookie consent banners, personal data export, and deletion requests.',
                'version' => '1.0.0',
                'default' => 'active',
            ],
            'recaptcha' => [
                'name'    => 'Google reCAPTCHA',
                'desc'    => 'Protect login, registration, checkout, and review forms from bots using Google reCAPTCHA v2 or v3.',
                'version' => '1.0.0',
                'default' => 'active',
            ],
            'sitemap' => [
                'name'    => 'Google Sitemap',
                'desc'    => 'Automatically generate an XML sitemap for Google and other search engines.',
                'version' => '1.0.0',
                'default' => 'active',
            ],
            'variations' => [
                'name'    => 'Product Variations',
                'desc'    => 'Create products with feature-based variants (color, size, etc.) as separate SKUs on one product page.',
                'version' => '1.0.0',
                'default' => 'active',
            ],
            'seo' => [
                'name'    => 'SEO',
                'desc'    => 'Search engine-friendly URLs, meta tags, canonical URLs, structured data, and Open Graph support.',
                'version' => '1.0.0',
                'default' => 'active',
            ],
            'price-per-unit' => [
                'name'    => 'Price Per Unit',
                'desc'    => 'Display price per unit (e.g. per kg, per liter) on catalog and product pages for transparent pricing.',
                'version' => '1.0.0',
                'default' => 'active',
            ],
            'wishlist' => [
                'name'    => 'Wish List',
                'desc'    => 'Let customers save products to personal wish lists for later purchase. Syncs across sessions.',
                'version' => '1.0.0',
                'default' => 'active',
            ],
            'social-buttons' => [
                'name'    => 'Social Buttons',
                'desc'    => 'Add share buttons for Facebook, X, Pinterest, and other social networks on product and content pages.',
                'version' => '1.0.0',
                'default' => 'disabled',
            ],
            'age-verification' => [
                'name'    => 'Age Verification',
                'desc'    => 'Toggle age restriction rules for products and categories. Require age confirmation before viewing or purchasing.',
                'version' => '1.0.0',
                'default' => 'disabled',
            ],
        ];
    }

    /* ══════════════════════════════════════════════════════════════════════
     * ROUTE REGISTRATION
     * ══════════════════════════════════════════════════════════════════════ */

    public function register_routes(): void {

        // GET /extensions — list all
        register_rest_route( $this->namespace, "/{$this->rest_base}", [
            'methods'             => WP_REST_Server::READABLE,
            'callback'            => [ $this, 'get_extensions' ],
            'permission_callback' => [ $this, 'admin_permission' ],
        ] );

        // PUT /extensions/{id} — toggle status
        register_rest_route( $this->namespace, "/{$this->rest_base}/(?P<id>[\\w-]+)", [
            'methods'             => 'PUT',
            'callback'            => [ $this, 'update_status' ],
            'permission_callback' => [ $this, 'admin_permission' ],
        ] );

        // GET /extensions/{id}/settings — get settings schema + values
        register_rest_route( $this->namespace, "/{$this->rest_base}/(?P<id>[\\w-]+)/settings", [
            [
                'methods'             => WP_REST_Server::READABLE,
                'callback'            => [ $this, 'get_settings' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
            [
                'methods'             => 'PUT',
                'callback'            => [ $this, 'update_settings' ],
                'permission_callback' => [ $this, 'admin_permission' ],
            ],
        ] );

    }

    public function admin_permission(): bool {
        return current_user_can( 'manage_options' );
    }


    /* ══════════════════════════════════════════════════════════════════════
     * GET /extensions — List all extensions with status
     * ══════════════════════════════════════════════════════════════════════ */

    public function get_extensions( WP_REST_Request $request ): WP_REST_Response {
        $db   = titancart_db();
        $defs = self::definitions();

        // Fetch stored statuses from tc_settings table
        // getHash returns flat key→value map: ['bestsellers' => 'active', ...]
        $rows = $db->getHash(
            "SELECT `key`, value FROM {$db->table('settings')} WHERE section = ?s",
            'extensions'
        );

        $result = [];
        foreach ( $defs as $id => $def ) {
            $stored_status = $rows[ $id ] ?? null;
            $result[] = [
                'id'      => $id,
                'name'    => $def['name'],
                'desc'    => $def['desc'],
                'version' => $def['version'],
                'status'  => $stored_status ?: $def['default'],
                'builtin' => true,
                // Edition gate (seam #4): mark Pro-only built-in extensions so the
                // Extensions admin badges + locks the toggle. `pro` is the LOCKED
                // classification; the SPA computes locked = pro && !Config.isPro
                // (INERT on Pro, where nothing is locked).
                'pro'     => \TitanCart\Core\Edition::is_pro_extension( $id ),
                'has_settings' => method_exists( self::class, 'schema_' . str_replace( '-', '_', $id ) ),
            ];
        }

        return new WP_REST_Response( $result );
    }

    /* ══════════════════════════════════════════════════════════════════════
     * PUT /extensions/{id} — Toggle extension status
     * ══════════════════════════════════════════════════════════════════════ */

    public function update_status( WP_REST_Request $request ): WP_REST_Response {
        $id   = sanitize_key( $request->get_param( 'id' ) );
        $defs = self::definitions();

        if ( ! isset( $defs[ $id ] ) ) {
            return new WP_REST_Response( [ 'code' => 'unknown_extension', 'message' => 'Unknown extension.' ], 404 );
        }

        $body   = $request->get_json_params();
        $status = isset( $body['status'] ) && $body['status'] === 'active' ? 'active' : 'disabled';


        $db    = titancart_db();
        $table = $db->table( 'settings' );

        $now = titancart_now_utc(); // KI-24: explicit UTC (Phase 3 drops the ON UPDATE/DEFAULT)
        $db->query(
            "INSERT INTO {$table} (section, `key`, value, autoload, updated_at)
             VALUES ('extensions', ?s, ?s, 1, ?s)
             ON DUPLICATE KEY UPDATE value = ?s, updated_at = ?s",
            $id, $status, $now, $status, $now
        );

        return new WP_REST_Response( [
            'success' => true,
            'id'      => $id,
            'status'  => $status,
        ] );
    }

    /* ══════════════════════════════════════════════════════════════════════
     * Helper: check if an extension is active (for use by other modules)
     * ══════════════════════════════════════════════════════════════════════ */

    public static function is_active( string $id ): bool {
        $defs = self::definitions();
        if ( ! isset( $defs[ $id ] ) ) {
            return false;
        }


        $db     = titancart_db();
        $stored = $db->getField(
            "SELECT value FROM {$db->table('settings')} WHERE section = 'extensions' AND `key` = ?s LIMIT 1",
            $id
        );

        if ( $stored !== null ) {
            return $stored === 'active';
        }

        return ( $defs[ $id ]['default'] ?? 'disabled' ) === 'active';
    }

    /* ══════════════════════════════════════════════════════════════════════
     * SECTION MAP — maps extension ID to the tc_settings section name.
     *
     * CRITICAL: The section name MUST match what the module's PHP code
     * reads via $db->getField("... WHERE section = ?s ...", $section).
     *
     * - 'reviews' → ReviewManager reads section='reviews'
     * - 'sitemap' → uses 'google_sitemap' (legacy — originally chosen to
     *               avoid collision with the now-removed Settings → Sitemap
     *               sub-tab; preserved for data-stability of existing rows)
     * - All others use the extension ID directly.
     * ══════════════════════════════════════════════════════════════════════ */

    private static function section_for( string $id ): string {
        $map = [
            'reviews'    => 'reviews',        // ReviewManager reads section='reviews'
            'sitemap'    => 'google_sitemap', // Legacy section name; preserved for existing data
            'gift-cards' => 'gift_cards',     // Normalize hyphen for DB section
        ];
        return $map[ $id ] ?? str_replace( '-', '_', $id );
    }

    /* ══════════════════════════════════════════════════════════════════════
     * GET /extensions/{id}/settings — Extension-specific settings
     * ══════════════════════════════════════════════════════════════════════ */

    public function get_settings( WP_REST_Request $request ): WP_REST_Response {
        $id     = sanitize_key( $request->get_param( 'id' ) );
        $method = 'schema_' . str_replace( '-', '_', $id );

        if ( ! method_exists( self::class, $method ) ) {
            return new WP_REST_Response( [ 'code' => 'no_settings', 'message' => 'This extension has no settings.' ], 404 );
        }

        $schema  = self::$method();
        $section = self::section_for( $id );
        $db      = titancart_db();

        // Fetch current values
        $rows   = $db->getArray(
            "SELECT `key`, value FROM {$db->table('settings')} WHERE section = ?s",
            $section
        );
        $values = [];
        foreach ( $rows as $row ) {
            $values[ $row['key'] ] = $row['value'];
        }

        // Never expose a stored secret to the browser. Mask password-type fields
        // in BOTH the schema (field.value) and the flat values map; report only
        // whether one is set so the UI can show "leave blank to keep current".
        $secrets_set = [];
        foreach ( $schema['groups'] as &$group ) {
            foreach ( $group['fields'] as &$field ) {
                if ( ( $field['type'] ?? 'text' ) === 'password' ) {
                    $k                 = $field['key'];
                    $secrets_set[ $k ] = ( isset( $values[ $k ] ) && $values[ $k ] !== '' );
                    $field['value']    = '';
                    $values[ $k ]      = '';
                    continue;
                }
                $field['value'] = $values[ $field['key'] ] ?? $field['default'] ?? '';
            }
        }
        unset( $group, $field );

        return new WP_REST_Response( [
            'section'     => $section,
            'schema'      => $schema,
            'values'      => $values,
            'secrets_set' => $secrets_set,
        ] );
    }

    /* ══════════════════════════════════════════════════════════════════════
     * PUT /extensions/{id}/settings — Save extension settings
     * ══════════════════════════════════════════════════════════════════════ */

    public function update_settings( WP_REST_Request $request ): WP_REST_Response {
        $id     = sanitize_key( $request->get_param( 'id' ) );
        $method = 'schema_' . str_replace( '-', '_', $id );

        if ( ! method_exists( self::class, $method ) ) {
            return new WP_REST_Response( [ 'code' => 'no_settings', 'message' => 'This extension has no settings.' ], 404 );
        }

        $schema  = self::$method();
        $section = self::section_for( $id );
        $body    = $request->get_json_params();
        $db      = titancart_db();
        $table   = $db->table( 'settings' );

        // Build valid keys from schema
        $valid_keys = [];
        foreach ( $schema['groups'] as $group ) {
            foreach ( $group['fields'] as $field ) {
                $valid_keys[ $field['key'] ] = $field;
            }
        }

        $updated = 0;
        foreach ( $body as $key => $value ) {
            $key = sanitize_key( $key );
            if ( ! isset( $valid_keys[ $key ] ) ) {
                continue;
            }

            // Password/secret fields: a blank submission means "keep current"
            // (the GET never returns the stored secret). Only overwrite when a
            // new value is entered — re-saving the page can't clobber a secret.
            if ( ( $valid_keys[ $key ]['type'] ?? 'text' ) === 'password' && (string) $value === '' ) {
                continue;
            }

            $value = self::sanitize_value( $value, $valid_keys[ $key ] );

            $now = titancart_now_utc(); // KI-24: explicit UTC (Phase 3 drops the ON UPDATE/DEFAULT)
            $db->query(
                "INSERT INTO {$table} (section, `key`, value, autoload, updated_at)
                 VALUES (?s, ?s, ?s, 0, ?s)
                 ON DUPLICATE KEY UPDATE value = ?s, updated_at = ?s",
                $section, $key, $value, $now, $value, $now
            );
            $updated++;
        }

        return new WP_REST_Response( [ 'success' => true, 'updated' => $updated ] );
    }

    /* ── Value sanitization (same pattern as SettingsController) ── */

    private static function sanitize_value( $value, array $field ): string {
        $type = $field['type'] ?? 'text';
        switch ( $type ) {
            case 'checkbox':
                return ( $value === true || $value === '1' || $value === 1 ) ? '1' : '0';
            case 'number':
                return (string) floatval( $value );
            case 'select':
                $options = $field['options'] ?? [];
                $allowed = array_column( $options, 'value' );
                return in_array( (string) $value, $allowed, true ) ? (string) $value : (string) ( $field['default'] ?? '' );
            case 'password':
                // Preserve the raw secret; sanitize_text_field() would corrupt
                // valid passwords (strips "<", collapses whitespace, etc.).
                // Strip only control characters (incl. a stray CR/LF from paste).
                return preg_replace( '/[\x00-\x1F\x7F]/', '', (string) $value );
            default:
                return sanitize_text_field( (string) $value );
        }
    }

    /* ══════════════════════════════════════════════════════════════════════
     * EXTENSION SETTINGS SCHEMAS
     *
     * Each method is named schema_{id} (hyphens become underscores).
     * Format matches SettingsController: groups → fields.
     *
     * KEY NAMING RULE: field keys MUST match what the PHP module reads via
     * $this->setting('key_name'). When no module exists yet, keys follow
     * conventional addon settings patterns for forward-compatibility.
     * ══════════════════════════════════════════════════════════════════════ */

    // ─────────────────────────────────────────────────────────────────────
    // 1. BEST SELLERS  (section: bestsellers)
    //    Reference fields: final_sale_from, sales_amount_from, period, last_days
    // ─────────────────────────────────────────────────────────────────────
    private static function schema_bestsellers(): array {
        return [
            'title'  => 'Best Sellers',
            'groups' => [
                [
                    'id'     => 'general',
                    'title'  => 'General',
                    'fields' => [
                        [ 'key' => 'final_sale_from',   'label' => 'Final sale: discount from (%)',     'type' => 'number', 'default' => '40', 'hint' => 'Products with this discount or more appear in "On Sale" blocks.' ],
                        [ 'key' => 'sales_amount_from', 'label' => 'Minimum sales to appear in list',  'type' => 'number', 'default' => '1',  'hint' => 'A product must have sold at least this many units.' ],
                    ],
                ],
                [
                    'id'     => 'newest',
                    'title'  => 'Newest Products',
                    'fields' => [
                        [ 'key' => 'period',    'label' => 'Period',          'type' => 'select', 'default' => 'all',
                          'options' => [['value'=>'all','label'=>'All time'],['value'=>'today','label'=>'Today'],['value'=>'last_days','label'=>'Last N days']] ],
                        [ 'key' => 'last_days', 'label' => 'Number of days', 'type' => 'number', 'default' => '3', 'hint' => 'Used when period is "Last N days".' ],
                    ],
                ],
            ],
        ];
    }

    // ─────────────────────────────────────────────────────────────────────
    // 2. CUSTOMER PRODUCT REVIEWS  (section: reviews)
    //    ReviewManager reads: reviews_enabled, reviews_allow_guest,
    //    reviews_require_purchase, reviews_auto_approve, reviews_ip_check
    //    Reference fields: reviews_per_page, review_approval, review_fields, etc.
    // ─────────────────────────────────────────────────────────────────────
    private static function schema_reviews(): array {
        return [
            'title'  => 'Customer Product Reviews',
            'groups' => [
                [
                    'id'     => 'general',
                    'title'  => 'General',
                    'fields' => [
                        [ 'key' => 'reviews_enabled',          'label' => 'Enable product reviews',                   'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'reviews_per_page',         'label' => 'Reviews per page',                         'type' => 'number',   'default' => '10' ],
                        [ 'key' => 'reviews_allow_guest',      'label' => 'Allow guest reviews',                      'type' => 'checkbox', 'default' => '1', 'hint' => 'Non-logged-in visitors can leave reviews.' ],
                        [ 'key' => 'reviews_auto_approve',     'label' => 'Auto-approve new reviews',                 'type' => 'checkbox', 'default' => '0', 'hint' => 'When off, reviews go to a moderation queue.' ],
                        [ 'key' => 'reviews_ip_check',         'label' => 'Check for duplicate IP addresses',         'type' => 'checkbox', 'default' => '0', 'hint' => 'Prevent multiple reviews from the same IP.' ],
                        [ 'key' => 'reviews_require_purchase', 'label' => 'Only buyers can review',                   'type' => 'checkbox', 'default' => '0', 'hint' => 'Customer must have purchased the product.' ],
                    ],
                ],
                [
                    'id'     => 'display',
                    'title'  => 'Display',
                    'fields' => [
                        [ 'key' => 'reviews_form_fields', 'label' => 'Review form style', 'type' => 'select', 'default' => 'advanced',
                          'options' => [['value'=>'advanced','label'=>'Advanced (title + pros + cons + comment)'],['value'=>'simple','label'=>'Simple (rating + comment only)']] ],
                        [ 'key' => 'reviews_images_allowed', 'label' => 'Allow image uploads in reviews', 'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'reviews_customer_location', 'label' => 'Ask for customer location', 'type' => 'select', 'default' => 'none',
                          'options' => [['value'=>'none','label'=>'Do not ask'],['value'=>'country','label'=>'Country'],['value'=>'city','label'=>'City']] ],
                    ],
                ],
            ],
        ];
    }

    // ─────────────────────────────────────────────────────────────────────
    // 3. GDPR COMPLIANCE  (section: gdpr)
    //    Reference fields: gdpr_cookie_consent (none/implicit/explicit),
    //    privacy_policy_page, gdpr_settings_data (JSON)
    // ─────────────────────────────────────────────────────────────────────
    private static function schema_gdpr(): array {
        return [
            'title'  => 'GDPR Compliance',
            'groups' => [
                [
                    'id'     => 'cookie_consent',
                    'title'  => 'Cookie Consent',
                    'fields' => [
                        [ 'key' => 'gdpr_cookie_consent', 'label' => 'Cookie consent mode', 'type' => 'select', 'default' => 'explicit',
                          'options' => [['value'=>'none','label'=>'Disabled'],['value'=>'implicit','label'=>'Implicit (browsing = consent)'],['value'=>'explicit','label'=>'Explicit (must click Accept)']] ],
                        [ 'key' => 'cookie_banner_text', 'label' => 'Banner text', 'type' => 'textarea', 'default' => 'We use cookies to improve your experience. By continuing to browse, you agree to our use of cookies.' ],
                        [ 'key' => 'cookie_banner_position', 'label' => 'Banner position', 'type' => 'select', 'default' => 'bottom',
                          'options' => [['value'=>'bottom','label'=>'Bottom bar'],['value'=>'top','label'=>'Top bar'],['value'=>'popup','label'=>'Center popup']] ],
                    ],
                ],
                [
                    'id'     => 'data_privacy',
                    'title'  => 'Data Privacy',
                    'fields' => [
                        [ 'key' => 'privacy_policy_page',  'label' => 'Privacy Policy page URL',                'type' => 'text',     'default' => '/privacy-policy' ],
                        [ 'key' => 'allow_data_export',    'label' => 'Allow customers to export their data',   'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'allow_data_deletion',  'label' => 'Allow customers to request data deletion', 'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'data_retention_days',  'label' => 'Data retention hold (days)',             'type' => 'number',   'default' => '180', 'hint' => 'When a customer deletes their account, order-linked personal data (name, email, billing/shipping address on past orders) is kept this many days after their last order before being permanently anonymized — a hold for chargeback defense and legal-claim retention (GDPR Art.17(3)). 180 days (6 months) is recommended. Account login, addresses, wishlist and marketing data are removed immediately regardless. 0 = erase order data immediately too.' ],
                        [ 'key' => 'checkout_consent',     'label' => 'Require consent checkbox at checkout',   'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'checkout_consent_text','label' => 'Consent checkbox label',                 'type' => 'text',     'default' => 'I agree to the processing of my personal data' ],
                    ],
                ],
            ],
        ];
    }


    // ─────────────────────────────────────────────────────────────────────
    // 5. GOOGLE reCAPTCHA  (section: recaptcha)
    //    Reference fields: recaptcha_site_key, recaptcha_secret, recaptcha_theme,
    //    recaptcha_size, recaptcha_type, recaptcha_v3_site_key,
    //    recaptcha_v3_secret, recaptcha_v3_success_score
    // ─────────────────────────────────────────────────────────────────────
    private static function schema_recaptcha(): array {
        return [
            'title'  => 'Google reCAPTCHA',
            'groups' => [
                [
                    'id'     => 'mode',
                    'title'  => 'Mode',
                    'fields' => [
                        [ 'key' => 'recaptcha_version', 'label' => 'reCAPTCHA version', 'type' => 'select', 'default' => 'v2',
                          'options' => [['value'=>'v2','label'=>'v2 (checkbox widget)'],['value'=>'v3','label'=>'v3 (invisible, score-based)']] ],
                    ],
                ],
                [
                    'id'     => 'v2',
                    'title'  => 'reCAPTCHA v2 Settings',
                    'fields' => [
                        [ 'key' => 'recaptcha_site_key',  'label' => 'Site key',  'type' => 'text',     'default' => '' ],
                        [ 'key' => 'recaptcha_secret',    'label' => 'Secret key','type' => 'password', 'default' => '' ],
                        [ 'key' => 'recaptcha_theme',     'label' => 'Theme',     'type' => 'select',   'default' => 'light',
                          'options' => [['value'=>'light','label'=>'Light'],['value'=>'dark','label'=>'Dark']] ],
                        [ 'key' => 'recaptcha_size',      'label' => 'Size',      'type' => 'select',   'default' => 'normal',
                          'options' => [['value'=>'normal','label'=>'Normal'],['value'=>'compact','label'=>'Compact']] ],
                    ],
                ],
                [
                    'id'     => 'v3',
                    'title'  => 'reCAPTCHA v3 Settings',
                    'fields' => [
                        [ 'key' => 'recaptcha_v3_site_key',      'label' => 'v3 Site key',       'type' => 'text',     'default' => '' ],
                        [ 'key' => 'recaptcha_v3_secret',        'label' => 'v3 Secret key',     'type' => 'password', 'default' => '' ],
                        [ 'key' => 'recaptcha_v3_success_score', 'label' => 'v3 success score',  'type' => 'select',   'default' => '0.5',
                          'options' => [['value'=>'0.9','label'=>'0.9 (strict)'],['value'=>'0.7','label'=>'0.7'],['value'=>'0.5','label'=>'0.5 (recommended)'],['value'=>'0.3','label'=>'0.3'],['value'=>'0.1','label'=>'0.1 (permissive)']] ],
                    ],
                ],
                [
                    'id'     => 'forms',
                    'title'  => 'Protected Forms',
                    'fields' => [
                        [ 'key' => 'protect_login',    'label' => 'Login form',        'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'protect_register', 'label' => 'Registration form', 'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'protect_checkout', 'label' => 'Checkout (guest)',   'type' => 'checkbox', 'default' => '0' ],
                        [ 'key' => 'protect_reviews',  'label' => 'Review form',       'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'protect_contact',  'label' => 'Contact form',      'type' => 'checkbox', 'default' => '1' ],
                    ],
                ],
            ],
        ];
    }

    // ─────────────────────────────────────────────────────────────────────
    // 6. GOOGLE SITEMAP  (section: google_sitemap — see section_for() for
    //    why this differs from the extension id 'sitemap')
    //    Reference fields: include_products, products_change, products_priority,
    //    include_categories, categories_change, categories_priority,
    //    include_pages, pages_change, pages_priority
    // ─────────────────────────────────────────────────────────────────────
    private static function schema_sitemap(): array {
        $freq_options = [
            ['value'=>'always','label'=>'Always'],['value'=>'hourly','label'=>'Hourly'],
            ['value'=>'daily','label'=>'Daily'],['value'=>'weekly','label'=>'Weekly'],
            ['value'=>'monthly','label'=>'Monthly'],['value'=>'yearly','label'=>'Yearly'],
            ['value'=>'never','label'=>'Never'],
        ];
        $priority_options = [
            ['value'=>'0.0','label'=>'0.0'],['value'=>'0.1','label'=>'0.1'],
            ['value'=>'0.2','label'=>'0.2'],['value'=>'0.3','label'=>'0.3'],
            ['value'=>'0.4','label'=>'0.4'],['value'=>'0.5','label'=>'0.5'],
            ['value'=>'0.6','label'=>'0.6'],['value'=>'0.7','label'=>'0.7'],
            ['value'=>'0.8','label'=>'0.8'],['value'=>'0.9','label'=>'0.9'],
            ['value'=>'1.0','label'=>'1.0'],
        ];
        return [
            'title'  => 'Google Sitemap',
            'groups' => [
                [
                    'id'     => 'products',
                    'title'  => 'Products',
                    'fields' => [
                        [ 'key' => 'include_products',   'label' => 'Include products in sitemap', 'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'products_change',    'label' => 'Change frequency',            'type' => 'select',   'default' => 'daily', 'options' => $freq_options ],
                        [ 'key' => 'products_priority',  'label' => 'Priority',                    'type' => 'select',   'default' => '0.5',   'options' => $priority_options ],
                    ],
                ],
                [
                    'id'     => 'categories',
                    'title'  => 'Categories',
                    'fields' => [
                        [ 'key' => 'include_categories',   'label' => 'Include categories in sitemap', 'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'categories_change',    'label' => 'Change frequency',              'type' => 'select',   'default' => 'daily', 'options' => $freq_options ],
                        [ 'key' => 'categories_priority',  'label' => 'Priority',                      'type' => 'select',   'default' => '0.5',   'options' => $priority_options ],
                    ],
                ],
                [
                    'id'     => 'pages',
                    'title'  => 'Pages',
                    'fields' => [
                        [ 'key' => 'include_pages',   'label' => 'Include pages in sitemap', 'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'pages_change',    'label' => 'Change frequency',         'type' => 'select',   'default' => 'daily', 'options' => $freq_options ],
                        [ 'key' => 'pages_priority',  'label' => 'Priority',                 'type' => 'select',   'default' => '0.5',   'options' => $priority_options ],
                    ],
                ],
            ],
        ];
    }


    // ─────────────────────────────────────────────────────────────────────
    // 13. SEO
    //     Settings deferred — SEO tab in product editor was built from
    //     screenshots. Schema will be added when the full SEO module is
    //     properly implemented to avoid key mismatches.
    // ─────────────────────────────────────────────────────────────────────

    // ─────────────────────────────────────────────────────────────────────
    // 14. WISHLIST  (section: wishlist)
    //     Reference: no addon settings. TitanCart adds basic controls.
    // ─────────────────────────────────────────────────────────────────────
    private static function schema_wishlist(): array {
        return [
            'title'  => 'Wish List',
            'groups' => [
                [
                    'id'     => 'general',
                    'title'  => 'General',
                    'fields' => [
                        [ 'key' => 'allow_guest_wishlist', 'label' => 'Allow guest wish lists',           'type' => 'checkbox', 'default' => '1', 'hint' => 'Guests can save items via session cookie. Merged on login.' ],
                        [ 'key' => 'max_wishlist_items',   'label' => 'Maximum items per wish list',      'type' => 'number',   'default' => '50', 'hint' => '0 = unlimited.' ],
                        [ 'key' => 'show_in_header',       'label' => 'Show wishlist icon in header',     'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'show_on_cards',        'label' => 'Show heart button on product cards','type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'show_on_pdp',          'label' => 'Show wishlist button on product detail page', 'type' => 'checkbox', 'default' => '1' ],
                    ],
                ],
            ],
        ];
    }

    // ─────────────────────────────────────────────────────────────────────
    // 15. PRICE PER UNIT  (section: price_per_unit)
    //     Reference fields: units_in_product, show_price_per_x_units, unit_name
    //     on product level. TitanCart adds global defaults.
    // ─────────────────────────────────────────────────────────────────────
    private static function schema_price_per_unit(): array {
        return [
            'title'  => 'Price Per Unit',
            'groups' => [
                [
                    'id'     => 'general',
                    'title'  => 'General',
                    'fields' => [
                        [ 'key' => 'show_on_catalog',      'label' => 'Show per-unit price on catalog pages',       'type' => 'checkbox', 'default' => '1', 'hint' => 'Display "($X.XX per kg)" below product price on shop/category pages.' ],
                        [ 'key' => 'show_on_pdp',          'label' => 'Show per-unit price on product detail page', 'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'default_unit_name',    'label' => 'Default unit name',                          'type' => 'text',     'default' => 'kg', 'hint' => 'Used when no unit is specified on the product.' ],
                        [ 'key' => 'default_units_in_product', 'label' => 'Default units in product',              'type' => 'number',   'default' => '1',  'hint' => 'Default quantity of units per product (e.g. 0.5 for 500g).' ],
                        [ 'key' => 'default_show_per_x',   'label' => 'Default display per X units',               'type' => 'number',   'default' => '1',  'hint' => 'Show price per this many units (e.g. 100 for "per 100g").' ],
                    ],
                ],
            ],
        ];
    }

    // ─────────────────────────────────────────────────────────────────────
    // 16. SOCIAL BUTTONS  (section: social_buttons)
    //     Reference: per-network enable + display_on (products/pages).
    //     TitanCart simplifies to toggles + placement.
    // ─────────────────────────────────────────────────────────────────────
    private static function schema_social_buttons(): array {
        return [
            'title'  => 'Social Buttons',
            'groups' => [
                [
                    'id'     => 'networks',
                    'title'  => 'Enabled Networks',
                    'fields' => [
                        [ 'key' => 'enable_facebook',  'label' => 'Facebook Share',           'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'enable_x',         'label' => 'X (Twitter) Share',        'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'enable_pinterest',  'label' => 'Pinterest Pin',            'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'enable_linkedin',   'label' => 'LinkedIn Share',           'type' => 'checkbox', 'default' => '0' ],
                        [ 'key' => 'enable_whatsapp',   'label' => 'WhatsApp Share',           'type' => 'checkbox', 'default' => '0' ],
                        [ 'key' => 'enable_email',      'label' => 'Email Share',              'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'enable_copy_link',  'label' => 'Copy Link',                'type' => 'checkbox', 'default' => '1' ],
                    ],
                ],
                [
                    'id'     => 'network_settings',
                    'title'  => 'Network Settings',
                    'fields' => [
                        [ 'key' => 'facebook_app_id',   'label' => 'Facebook App ID',          'type' => 'text',     'default' => '', 'hint' => 'Required for Facebook Share to work. Get one at developers.facebook.com.' ],
                        [ 'key' => 'x_via',             'label' => 'X (Twitter) "via" username','type' => 'text',    'default' => '', 'hint' => 'Username to attribute tweets to (e.g. "titancart" without @).' ],
                        [ 'key' => 'pinterest_size',    'label' => 'Pinterest button size',    'type' => 'select',   'default' => 'small',
                          'options' => [['value'=>'small','label'=>'Small'],['value'=>'large','label'=>'Large']] ],
                        [ 'key' => 'pinterest_shape',   'label' => 'Pinterest button shape',   'type' => 'select',   'default' => 'rect',
                          'options' => [['value'=>'rect','label'=>'Rectangular'],['value'=>'round','label'=>'Circular']] ],
                    ],
                ],
                [
                    'id'     => 'display',
                    'title'  => 'Display Settings',
                    'fields' => [
                        [ 'key' => 'show_on_products', 'label' => 'Show on product detail pages', 'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'show_on_pages',    'label' => 'Show on content pages',        'type' => 'checkbox', 'default' => '0' ],
                        [ 'key' => 'show_on_blog',     'label' => 'Show on blog posts',           'type' => 'checkbox', 'default' => '1' ],
                        [ 'key' => 'button_style',     'label' => 'Button style',                 'type' => 'select',   'default' => 'icon_only',
                          'options' => [['value'=>'icon_only','label'=>'Icon only'],['value'=>'icon_label','label'=>'Icon + label']] ],
                        [ 'key' => 'button_position',  'label' => 'Position on product page',     'type' => 'select',   'default' => 'below_cart',
                          'options' => [['value'=>'below_cart','label'=>'Below Add to Cart'],['value'=>'below_description','label'=>'Below description'],['value'=>'floating_left','label'=>'Floating left sidebar']] ],
                    ],
                ],
            ],
        ];
    }


    // ─────────────────────────────────────────────────────────────────────
    // 18. AGE VERIFICATION  (section: age_verification)
    //     Reference fields: product/category level fields (age_limit,
    //     age_warning_message). TitanCart adds global defaults.
    // ─────────────────────────────────────────────────────────────────────
    private static function schema_age_verification(): array {
        return [
            'title'  => 'Age Verification',
            'groups' => [
                [
                    'id'     => 'general',
                    'title'  => 'General',
                    'fields' => [
                        [ 'key' => 'default_age_limit', 'label' => 'Default minimum age',              'type' => 'number',   'default' => '18', 'hint' => 'Applied to products/categories that have age restriction enabled.' ],
                        [ 'key' => 'verification_type', 'label' => 'Verification method',              'type' => 'select',   'default' => 'birthday',
                          'options' => [['value'=>'birthday','label'=>'Enter date of birth'],['value'=>'confirm','label'=>'Simple "I am over X" confirmation'],['value'=>'checkbox','label'=>'Checkbox acknowledgment']] ],
                        [ 'key' => 'warning_message',   'label' => 'Warning message',                  'type' => 'textarea', 'default' => 'This product is age-restricted. You must be at least {age} years old to view or purchase this item.' ],
                        [ 'key' => 'deny_action',       'label' => 'Action if age not met',            'type' => 'select',   'default' => 'redirect',
                          'options' => [['value'=>'redirect','label'=>'Redirect to homepage'],['value'=>'message','label'=>'Show denial message'],['value'=>'hide','label'=>'Hide product entirely']] ],
                        [ 'key' => 'remember_days',     'label' => 'Remember verification (days)',     'type' => 'number',   'default' => '30', 'hint' => 'Days to remember age verification in cookie. 0 = ask every visit.' ],
                    ],
                ],
                [
                    'id'     => 'site_wide',
                    'title'  => 'Site-wide Gate',
                    'fields' => [
                        [ 'key' => 'site_wide_enabled', 'label' => 'Gate the whole site',              'type' => 'checkbox', 'default' => '0', 'hint' => 'When on, visitors must verify before viewing any storefront page (including login). Uses the same cookie as the product/category gates, so a single verification satisfies all three unless a higher age is required downstream.' ],
                        [ 'key' => 'site_age_limit',    'label' => 'Site-wide minimum age',            'type' => 'number',   'default' => '18', 'hint' => 'Leave 0 to use the global default above.' ],
                        [ 'key' => 'site_message',      'label' => 'Site-wide gate message',           'type' => 'textarea', 'default' => 'This site contains age-restricted content. You must be at least {age} years old to enter.' ],
                    ],
                ],
            ],
        ];
    }

}
