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

class TMNL_Admin {

    private $adapters = array();

    public function __construct() {
        add_action( 'admin_menu',            array( $this, 'add_menu' ) );
        add_action( 'admin_enqueue_scripts', array( $this, 'enqueue_styles' ) );
        add_action( 'wp_ajax_tmnl_test_api_key',       array( $this, 'ajax_test_api_key' ) );
        add_action( 'wp_ajax_tmnl_live_preview',       array( $this, 'ajax_live_preview' ) );
        add_action( 'wp_ajax_tmnl_wizard_save_step',   array( $this, 'ajax_wizard_save_step' ) );
        add_action( 'wp_ajax_tmnl_save_google',        array( $this, 'ajax_save_google' ) );
        add_action( 'wp_ajax_tmnl_fetch_google',       array( $this, 'ajax_fetch_google' ) );
        add_action( 'wp_ajax_tmnl_save_display',       array( $this, 'ajax_save_display' ) );
        add_action( 'wp_ajax_tmnl_save_testimonial',   array( $this, 'ajax_save_testimonial' ) );
        add_action( 'wp_ajax_tmnl_delete_testimonial', array( $this, 'ajax_delete_testimonial' ) );
        add_action( 'wp_ajax_tmnl_toggle_testimonial', array( $this, 'ajax_toggle_testimonial' ) );
        add_action( 'wp_ajax_tmnl_add_x_embed',        array( $this, 'ajax_add_x_embed' ) );
        add_action( 'wp_ajax_tmnl_delete_x_embed',     array( $this, 'ajax_delete_x_embed' ) );
        add_action( 'wp_ajax_tmnl_toggle_x_embed',     array( $this, 'ajax_toggle_x_embed' ) );
    }

    public function set_adapters( $adapters ) {
        $this->adapters = $adapters;
    }

    private function get_adapter( $id ) {
        return $this->adapters[ $id ] ?? null;
    }

    // =========================================
    // Menu
    // =========================================

    public function add_menu() {
        add_menu_page(
            __( 'Kuchikomi Wall', 'elplan-kuchikomi-wall' ),
            __( 'Kuchikomi Wall', 'elplan-kuchikomi-wall' ),
            'manage_options',
            'tmnl-dashboard',
            array( $this, 'page_dashboard' ),
            'dashicons-format-quote',
            30
        );
        add_submenu_page( null, __( 'Setup Wizard', 'elplan-kuchikomi-wall' ), '', 'manage_options', 'tmnl-setup', array( $this, 'page_wizard' ) );
    }

    public function enqueue_styles( $hook ) {
        if ( strpos( $hook, 'tmnl' ) === false ) return;
        wp_add_inline_style( 'wp-admin', $this->get_admin_css() );
    }

    // =========================================
    // Helpers
    // =========================================

    private function stars_html( $rating ) {
        $html = '<span class="tmnl-stars">';
        for ( $i = 1; $i <= 5; $i++ ) {
            $html .= ( $i <= $rating ) ? '★' : '☆';
        }
        return $html . '</span>';
    }

    // =========================================
    // Dashboard — single page
    // =========================================

    public function page_dashboard() {
        $nonces = array(
            'test_api_key'       => wp_create_nonce( 'tmnl_test_api_key' ),
            'live_preview'       => wp_create_nonce( 'tmnl_live_preview' ),
            'save_google'        => wp_create_nonce( 'tmnl_save_google' ),
            'fetch_google'       => wp_create_nonce( 'tmnl_fetch_google' ),
            'save_display'       => wp_create_nonce( 'tmnl_save_display' ),
            'save_testimonial'   => wp_create_nonce( 'tmnl_save_testimonial' ),
            'delete_testimonial' => wp_create_nonce( 'tmnl_delete_testimonial' ),
            'toggle_testimonial' => wp_create_nonce( 'tmnl_toggle_testimonial' ),
            'add_x_embed'        => wp_create_nonce( 'tmnl_add_x_embed' ),
            'delete_x_embed'     => wp_create_nonce( 'tmnl_delete_x_embed' ),
            'toggle_x_embed'     => wp_create_nonce( 'tmnl_toggle_x_embed' ),
        );
        ?>
        <div class="wrap tmnl-wrap">
            <h1 class="tmnl-page-title">
                <span class="dashicons dashicons-format-quote"></span>
                <?php esc_html_e( 'Kuchikomi Wall', 'elplan-kuchikomi-wall' ); ?>
            </h1>
            <div id="tmnl-notice-area"></div>
            <?php
            $this->render_google_section();
            $this->render_manual_section();
            $this->render_x_section();
            $this->render_display_section();
            $this->render_shortcode_section();
            $this->render_upgrade_banner();
            $this->render_scripts( $nonces );
            ?>
        </div>
        <?php
    }

    // =========================================
    // Section: Google Reviews
    // =========================================

    private function render_google_section() {
        $adapter  = $this->get_adapter( 'google' );
        $settings = get_option( 'tmnl_source_google', array() );
        $api_key  = $settings['api_key']  ?? '';
        $place_id = $settings['place_id'] ?? '';
        $status   = $adapter ? $adapter->get_status() : array();

        $locale        = get_locale();
        $api_guide_url = ( 'ja' === substr( $locale, 0, 2 ) )
            ? 'https://www.el-plan.com/kuchikomi-wall/api-guide/'
            : 'https://www.el-plan.com/kuchikomi-wall/api-guide-en/';
        ?>
        <div class="tmnl-section" id="tmnl-section-google">
            <div class="tmnl-section-header">
                <span class="dashicons dashicons-google tmnl-section-icon"></span>
                <h2 class="tmnl-section-title"><?php esc_html_e( 'Google Reviews', 'elplan-kuchikomi-wall' ); ?></h2>
                <?php if ( ! empty( $status['place_name'] ) ) : ?>
                <span class="tmnl-section-meta">
                    <?php echo esc_html( $status['place_name'] ); ?>
                    &nbsp;<?php echo wp_kses( $this->stars_html( round( $status['place_rating'] ?? 0 ) ), array( 'span' => array( 'class' => array() ) ) ); ?>
                    <?php echo esc_html( $status['place_rating'] ?? '' ); ?>
                    (<?php echo esc_html( $status['place_count'] ?? 0 ); ?> <?php esc_html_e( 'reviews', 'elplan-kuchikomi-wall' ); ?>)
                </span>
                <?php endif; ?>
            </div>
            <div class="tmnl-section-body">
                <div class="tmnl-form-row">
                    <label class="tmnl-form-label">
                        <?php esc_html_e( 'API Key', 'elplan-kuchikomi-wall' ); ?>
                        <a href="<?php echo esc_url( $api_guide_url ); ?>" target="_blank" rel="noopener noreferrer" class="tmnl-help-link"><?php esc_html_e( 'How to get a key →', 'elplan-kuchikomi-wall' ); ?></a>
                    </label>
                    <div class="tmnl-form-control">
                        <input type="password" id="tmnl-google-api-key" class="regular-text"
                            value="<?php echo esc_attr( $api_key ); ?>" placeholder="AIza..." autocomplete="off">
                        <button type="button" class="button" id="tmnl-test-api-key"><?php esc_html_e( 'Test', 'elplan-kuchikomi-wall' ); ?></button>
                        <span id="tmnl-api-key-result"></span>
                    </div>
                </div>
                <div class="tmnl-form-row">
                    <label class="tmnl-form-label">
                        <?php esc_html_e( 'Place ID', 'elplan-kuchikomi-wall' ); ?>
                        <a href="https://developers.google.com/maps/documentation/javascript/examples/places-placeid-finder" target="_blank" rel="noopener noreferrer" class="tmnl-help-link"><?php esc_html_e( 'Find your Place ID →', 'elplan-kuchikomi-wall' ); ?></a>
                    </label>
                    <div class="tmnl-form-control">
                        <input type="text" id="tmnl-google-place-id" class="regular-text"
                            value="<?php echo esc_attr( $place_id ); ?>" placeholder="ChIJ...">
                    </div>
                </div>
                <div class="tmnl-form-actions">
                    <button type="button" class="button button-primary" id="tmnl-save-google"><?php esc_html_e( 'Save Settings', 'elplan-kuchikomi-wall' ); ?></button>
                    <button type="button" class="button" id="tmnl-fetch-google"><?php esc_html_e( 'Fetch Reviews Now', 'elplan-kuchikomi-wall' ); ?></button>
                    <?php if ( ! empty( $status['updated_at'] ) ) : ?>
                    <span class="tmnl-last-updated"><?php esc_html_e( 'Last fetched:', 'elplan-kuchikomi-wall' ); ?> <?php echo esc_html( $status['updated_at'] ); ?></span>
                    <?php endif; ?>
                </div>
                <div id="tmnl-google-fetch-result"></div>
                <div id="tmnl-google-reviews-wrap"><?php echo $this->get_google_reviews_html(); ?></div>
            </div>
        </div>
        <?php
    }

    public function get_google_reviews_html() {
        $adapter = $this->get_adapter( 'google' );
        if ( ! $adapter ) return '';
        $reviews = $adapter->get_normalized_reviews( 1 );
        if ( empty( $reviews ) ) return '';

        $html  = '<div class="tmnl-reviews-grid">';
        $html .= '<h3 class="tmnl-subsection-title">' . esc_html__( 'Cached Reviews', 'elplan-kuchikomi-wall' ) . ' <span class="tmnl-count">(' . count( $reviews ) . ')</span></h3>';
        $html .= '<div class="tmnl-mini-cards">';
        foreach ( $reviews as $r ) {
            $html .= '<div class="tmnl-mini-card">';
            $html .= '<div class="tmnl-mini-card-header">';
            if ( ! empty( $r['icon'] ) ) {
                $html .= '<img src="' . esc_url( $r['icon'] ) . '" class="tmnl-mini-avatar" alt="">';
            }
            $html .= '<div><strong>' . esc_html( $r['author_name'] ) . '</strong>';
            $html .= '<span class="tmnl-stars" style="color:#f5a623;font-size:12px;margin-left:4px;">' . str_repeat( '★', intval( $r['rating'] ) ) . '</span></div>';
            $html .= '</div>';
            $html .= '<p class="tmnl-mini-text">' . esc_html( mb_substr( $r['text'], 0, 80 ) ) . ( mb_strlen( $r['text'] ) > 80 ? '…' : '' ) . '</p>';
            if ( ! empty( $r['date'] ) ) {
                $html .= '<span class="tmnl-mini-date">' . esc_html( $r['date'] ) . '</span>';
            }
            $html .= '</div>';
        }
        $html .= '</div></div>';
        return $html;
    }

    // =========================================
    // Section: Manual Testimonials
    // =========================================

    private function render_manual_section() {
        $count = count( TMNL_DB::get_testimonials( array( 'visible_only' => false, 'source_type' => 'manual' ) ) );
        ?>
        <div class="tmnl-section tmnl-section-collapsed" id="tmnl-section-manual">
            <div class="tmnl-section-header tmnl-accordion-trigger">
                <span class="dashicons dashicons-admin-comments tmnl-section-icon"></span>
                <h2 class="tmnl-section-title"><?php esc_html_e( 'Manual Testimonials', 'elplan-kuchikomi-wall' ); ?></h2>
                <span class="tmnl-section-meta"><?php echo esc_html( $count ); ?> <?php esc_html_e( 'entries', 'elplan-kuchikomi-wall' ); ?></span>
                <span class="tmnl-accordion-arrow dashicons dashicons-arrow-down-alt2"></span>
            </div>
            <div class="tmnl-section-body" style="display:none;">
                <div id="tmnl-manual-form-wrap" style="display:none;">
                    <h3 class="tmnl-subsection-title" id="tmnl-manual-form-title"><?php esc_html_e( 'Add Testimonial', 'elplan-kuchikomi-wall' ); ?></h3>
                    <input type="hidden" id="tmnl-manual-id" value="">
                    <table class="form-table tmnl-form-table">
                        <tr>
                            <th><label for="tmnl-m-author"><?php esc_html_e( 'Author', 'elplan-kuchikomi-wall' ); ?></label></th>
                            <td><input type="text" id="tmnl-m-author" class="regular-text"></td>
                        </tr>
                        <tr>
                            <th><label for="tmnl-m-rating"><?php esc_html_e( 'Rating', 'elplan-kuchikomi-wall' ); ?></label></th>
                            <td>
                                <select id="tmnl-m-rating">
                                    <?php for ( $i = 5; $i >= 1; $i-- ) : ?>
                                    <option value="<?php echo esc_attr( $i ); ?>"><?php echo esc_html( str_repeat( '★', $i ) . str_repeat( '☆', 5 - $i ) ); ?></option>
                                    <?php endfor; ?>
                                </select>
                            </td>
                        </tr>
                        <tr>
                            <th><label for="tmnl-m-text"><?php esc_html_e( 'Content', 'elplan-kuchikomi-wall' ); ?></label></th>
                            <td><textarea id="tmnl-m-text" rows="4" class="large-text"></textarea></td>
                        </tr>
                        <tr>
                            <th><label for="tmnl-m-date"><?php esc_html_e( 'Date', 'elplan-kuchikomi-wall' ); ?></label></th>
                            <td><input type="date" id="tmnl-m-date" value="<?php echo esc_attr( date( 'Y-m-d' ) ); ?>"></td>
                        </tr>
                        <tr>
                            <th><label for="tmnl-m-source"><?php esc_html_e( 'Source', 'elplan-kuchikomi-wall' ); ?></label></th>
                            <td><input type="text" id="tmnl-m-source" class="regular-text"
                                placeholder="<?php echo esc_attr__( 'e.g. Coconala, Email', 'elplan-kuchikomi-wall' ); ?>"></td>
                        </tr>
                        <tr>
                            <th><?php esc_html_e( 'Visibility', 'elplan-kuchikomi-wall' ); ?></th>
                            <td><label><input type="checkbox" id="tmnl-m-visible" checked value="1"> <?php esc_html_e( 'Show on site', 'elplan-kuchikomi-wall' ); ?></label></td>
                        </tr>
                    </table>
                    <div class="tmnl-form-actions">
                        <button type="button" class="button button-primary" id="tmnl-manual-save"><?php esc_html_e( 'Save', 'elplan-kuchikomi-wall' ); ?></button>
                        <button type="button" class="button" id="tmnl-manual-cancel"><?php esc_html_e( 'Cancel', 'elplan-kuchikomi-wall' ); ?></button>
                    </div>
                </div>
                <div id="tmnl-manual-list-wrap">
                    <div class="tmnl-list-header">
                        <button type="button" class="button" id="tmnl-manual-add-btn">+ <?php esc_html_e( 'Add Testimonial', 'elplan-kuchikomi-wall' ); ?></button>
                    </div>
                    <div id="tmnl-manual-list"><?php echo $this->get_testimonials_html(); ?></div>
                </div>
            </div>
        </div>
        <?php
    }

    public function get_testimonials_html() {
        $items = TMNL_DB::get_testimonials( array( 'visible_only' => false, 'source_type' => 'manual' ) );
        if ( empty( $items ) ) {
            return '<p class="tmnl-empty-msg">' . esc_html__( 'No testimonials yet.', 'elplan-kuchikomi-wall' ) . '</p>';
        }
        $html  = '<table class="wp-list-table widefat fixed striped tmnl-list-table"><thead><tr>';
        $html .= '<th>' . esc_html__( 'Author', 'elplan-kuchikomi-wall' ) . '</th>';
        $html .= '<th>' . esc_html__( 'Rating', 'elplan-kuchikomi-wall' ) . '</th>';
        $html .= '<th>' . esc_html__( 'Content', 'elplan-kuchikomi-wall' ) . '</th>';
        $html .= '<th>' . esc_html__( 'Status', 'elplan-kuchikomi-wall' ) . '</th>';
        $html .= '<th>' . esc_html__( 'Actions', 'elplan-kuchikomi-wall' ) . '</th>';
        $html .= '</tr></thead><tbody>';
        foreach ( $items as $item ) {
            $row_class  = $item->is_visible ? '' : ' class="tmnl-hidden-row"';
            $badge_cls  = $item->is_visible ? 'tmnl-badge-visible' : 'tmnl-badge-hidden';
            $badge_lbl  = $item->is_visible ? esc_html__( 'Visible', 'elplan-kuchikomi-wall' ) : esc_html__( 'Hidden', 'elplan-kuchikomi-wall' );
            $toggle_lbl = $item->is_visible ? esc_html__( 'Hide', 'elplan-kuchikomi-wall' ) : esc_html__( 'Show', 'elplan-kuchikomi-wall' );
            $html .= '<tr' . $row_class . '>';
            $html .= '<td><strong>' . esc_html( $item->author_name ) . '</strong>';
            if ( $item->source_label ) $html .= '<br><span class="tmnl-mini-meta">' . esc_html( $item->source_label ) . '</span>';
            $html .= '</td>';
            $html .= '<td><span class="tmnl-stars">' . str_repeat( '★', intval( $item->rating ) ) . '</span></td>';
            $html .= '<td>' . esc_html( mb_substr( $item->text, 0, 60 ) ) . ( mb_strlen( $item->text ) > 60 ? '…' : '' ) . '</td>';
            $html .= '<td><span class="tmnl-badge ' . $badge_cls . '">' . $badge_lbl . '</span></td>';
            $html .= '<td class="tmnl-row-actions">';
            $html .= '<button class="button button-small tmnl-edit-testimonial"'
                . ' data-id="' . intval( $item->id ) . '"'
                . ' data-author="' . esc_attr( $item->author_name ) . '"'
                . ' data-rating="' . intval( $item->rating ) . '"'
                . ' data-text="' . esc_attr( $item->text ) . '"'
                . ' data-date="' . esc_attr( $item->review_date ) . '"'
                . ' data-source="' . esc_attr( $item->source_label ) . '"'
                . ' data-visible="' . intval( $item->is_visible ) . '"'
                . '>' . esc_html__( 'Edit', 'elplan-kuchikomi-wall' ) . '</button>';
            $html .= '<button class="button button-small tmnl-toggle-testimonial" data-id="' . intval( $item->id ) . '">' . $toggle_lbl . '</button>';
            $html .= '<button class="button button-small tmnl-delete-testimonial" data-id="' . intval( $item->id ) . '" style="color:#a00;">' . esc_html__( 'Delete', 'elplan-kuchikomi-wall' ) . '</button>';
            $html .= '</td></tr>';
        }
        $html .= '</tbody></table>';
        return $html;
    }

    // =========================================
    // Section: X Embeds
    // =========================================

    private function render_x_section() {
        $embeds = TMNL_DB::get_x_embeds( array( 'visible_only' => false ) );
        ?>
        <div class="tmnl-section tmnl-section-collapsed" id="tmnl-section-x">
            <div class="tmnl-section-header tmnl-accordion-trigger">
                <span class="dashicons dashicons-twitter tmnl-section-icon"></span>
                <h2 class="tmnl-section-title"><?php esc_html_e( 'X (Twitter) Embeds', 'elplan-kuchikomi-wall' ); ?></h2>
                <span class="tmnl-section-meta"><?php echo esc_html( count( $embeds ) ); ?> <?php esc_html_e( 'entries', 'elplan-kuchikomi-wall' ); ?></span>
                <span class="tmnl-accordion-arrow dashicons dashicons-arrow-down-alt2"></span>
            </div>
            <div class="tmnl-section-body" style="display:none;">
                <div class="tmnl-form-row">
                    <label class="tmnl-form-label"><?php esc_html_e( 'Tweet URL', 'elplan-kuchikomi-wall' ); ?></label>
                    <div class="tmnl-form-control">
                        <input type="url" id="tmnl-x-url" class="regular-text" placeholder="https://x.com/user/status/...">
                        <button type="button" class="button button-primary" id="tmnl-add-x-embed"><?php esc_html_e( 'Add Tweet', 'elplan-kuchikomi-wall' ); ?></button>
                        <span id="tmnl-x-result"></span>
                    </div>
                </div>
                <div id="tmnl-x-list"><?php echo $this->get_x_embeds_html(); ?></div>
            </div>
        </div>
        <?php
    }

    public function get_x_embeds_html() {
        $embeds = TMNL_DB::get_x_embeds( array( 'visible_only' => false ) );
        if ( empty( $embeds ) ) {
            return '<p class="tmnl-empty-msg">' . esc_html__( 'No X embeds yet.', 'elplan-kuchikomi-wall' ) . '</p>';
        }
        $html  = '<table class="wp-list-table widefat fixed striped tmnl-list-table"><thead><tr>';
        $html .= '<th>' . esc_html__( 'Author', 'elplan-kuchikomi-wall' ) . '</th>';
        $html .= '<th>' . esc_html__( 'URL', 'elplan-kuchikomi-wall' ) . '</th>';
        $html .= '<th>' . esc_html__( 'Status', 'elplan-kuchikomi-wall' ) . '</th>';
        $html .= '<th>' . esc_html__( 'Actions', 'elplan-kuchikomi-wall' ) . '</th>';
        $html .= '</tr></thead><tbody>';
        foreach ( $embeds as $embed ) {
            $row_class  = $embed->is_visible ? '' : ' class="tmnl-hidden-row"';
            $badge_cls  = $embed->is_visible ? 'tmnl-badge-visible' : 'tmnl-badge-hidden';
            $badge_lbl  = $embed->is_visible ? esc_html__( 'Visible', 'elplan-kuchikomi-wall' ) : esc_html__( 'Hidden', 'elplan-kuchikomi-wall' );
            $toggle_lbl = $embed->is_visible ? esc_html__( 'Hide', 'elplan-kuchikomi-wall' ) : esc_html__( 'Show', 'elplan-kuchikomi-wall' );
            $html .= '<tr' . $row_class . '>';
            $html .= '<td>' . esc_html( $embed->author ) . '</td>';
            $html .= '<td><a href="' . esc_url( $embed->tweet_url ) . '" target="_blank" rel="noopener noreferrer">' . esc_html( $embed->tweet_url ) . '</a></td>';
            $html .= '<td><span class="tmnl-badge ' . $badge_cls . '">' . $badge_lbl . '</span></td>';
            $html .= '<td class="tmnl-row-actions">';
            $html .= '<button class="button button-small tmnl-toggle-x-embed" data-id="' . intval( $embed->id ) . '">' . $toggle_lbl . '</button>';
            $html .= '<button class="button button-small tmnl-delete-x-embed" data-id="' . intval( $embed->id ) . '" style="color:#a00;">' . esc_html__( 'Delete', 'elplan-kuchikomi-wall' ) . '</button>';
            $html .= '</td></tr>';
        }
        $html .= '</tbody></table>';
        return $html;
    }

    // =========================================
    // Section: Display Settings
    // =========================================

    private function render_display_section() {
        $templates   = array(
            'card'     => __( 'Card Grid', 'elplan-kuchikomi-wall' ),
            'slider'   => __( 'Slider', 'elplan-kuchikomi-wall' ),
            'list'     => __( 'Simple List', 'elplan-kuchikomi-wall' ),
            'badge'    => __( 'Badge', 'elplan-kuchikomi-wall' ),
            'floating' => __( 'Floating', 'elplan-kuchikomi-wall' ),
        );
        $current_tpl = get_option( 'tmnl_template', 'card' );
        ?>
        <div class="tmnl-section" id="tmnl-section-display">
            <div class="tmnl-section-header">
                <span class="dashicons dashicons-admin-appearance tmnl-section-icon"></span>
                <h2 class="tmnl-section-title"><?php esc_html_e( 'Display Settings', 'elplan-kuchikomi-wall' ); ?></h2>
            </div>
            <div class="tmnl-section-body">
                <div class="tmnl-display-layout">
                    <div class="tmnl-display-form">
                        <h3 class="tmnl-subsection-title"><?php esc_html_e( 'Template', 'elplan-kuchikomi-wall' ); ?></h3>
                        <div class="tmnl-template-picker" id="tmnl-template-picker">
                            <?php foreach ( $templates as $val => $label ) : ?>
                            <label class="tmnl-tpl-option <?php echo $val === $current_tpl ? 'tmnl-tpl-active' : ''; ?>">
                                <input type="radio" name="tmnl_template" value="<?php echo esc_attr( $val ); ?>"
                                    <?php checked( $val, $current_tpl ); ?> style="display:none;">
                                <span class="tmnl-tpl-icon tmnl-tpl-icon-<?php echo esc_attr( $val ); ?>"></span>
                                <span><?php echo esc_html( $label ); ?></span>
                            </label>
                            <?php endforeach; ?>
                        </div>

                        <table class="form-table tmnl-form-table" style="margin-top:16px;">
                            <tr>
                                <th><?php esc_html_e( 'Color Scheme', 'elplan-kuchikomi-wall' ); ?></th>
                                <td>
                                    <select id="tmnl-color-scheme">
                                        <option value="light" <?php selected( get_option( 'tmnl_color_scheme', 'light' ), 'light' ); ?>><?php esc_html_e( 'Light', 'elplan-kuchikomi-wall' ); ?></option>
                                        <option value="dark"  <?php selected( get_option( 'tmnl_color_scheme', 'light' ), 'dark' ); ?>><?php esc_html_e( 'Dark', 'elplan-kuchikomi-wall' ); ?></option>
                                        <option value="auto"  <?php selected( get_option( 'tmnl_color_scheme', 'light' ), 'auto' ); ?>><?php esc_html_e( 'Auto', 'elplan-kuchikomi-wall' ); ?></option>
                                    </select>
                                </td>
                            </tr>
                            <tr id="tmnl-columns-row" <?php echo $current_tpl !== 'card' ? 'style="display:none;"' : ''; ?>>
                                <th><?php esc_html_e( 'Columns', 'elplan-kuchikomi-wall' ); ?></th>
                                <td>
                                    <select id="tmnl-columns">
                                        <?php for ( $c = 1; $c <= 4; $c++ ) : ?>
                                        <option value="<?php echo esc_attr( $c ); ?>" <?php selected( get_option( 'tmnl_default_columns', 3 ), $c ); ?>><?php echo esc_html( $c ); ?></option>
                                        <?php endfor; ?>
                                    </select>
                                </td>
                            </tr>
                            <tr>
                                <th><?php esc_html_e( 'Minimum Rating', 'elplan-kuchikomi-wall' ); ?></th>
                                <td>
                                    <select id="tmnl-min-rating">
                                        <?php for ( $i = 1; $i <= 5; $i++ ) : ?>
                                        <option value="<?php echo esc_attr( $i ); ?>" <?php selected( get_option( 'tmnl_min_rating', 1 ), $i ); ?>><?php printf( esc_html__( '%d stars and above', 'elplan-kuchikomi-wall' ), $i ); ?></option>
                                        <?php endfor; ?>
                                    </select>
                                </td>
                            </tr>
                            <tr>
                                <th><?php esc_html_e( 'Default Limit', 'elplan-kuchikomi-wall' ); ?></th>
                                <td><input type="number" id="tmnl-default-limit" class="small-text"
                                    value="<?php echo esc_attr( get_option( 'tmnl_default_limit', 6 ) ); ?>" min="1" max="50"></td>
                            </tr>
                        </table>

                        <h3 class="tmnl-subsection-title"><?php esc_html_e( 'Widget Options', 'elplan-kuchikomi-wall' ); ?></h3>
                        <table class="form-table tmnl-form-table">
                            <tr>
                                <th><?php esc_html_e( 'Show Author Photo', 'elplan-kuchikomi-wall' ); ?></th>
                                <td><label><input type="checkbox" id="tmnl-show-photo" value="1" <?php checked( get_option( 'tmnl_show_photo', 1 ), 1 ); ?>> <?php esc_html_e( 'Display avatar / profile photo', 'elplan-kuchikomi-wall' ); ?></label></td>
                            </tr>
                            <tr>
                                <th><?php esc_html_e( 'Show Review Date', 'elplan-kuchikomi-wall' ); ?></th>
                                <td><label><input type="checkbox" id="tmnl-show-date" value="1" <?php checked( get_option( 'tmnl_show_date', 1 ), 1 ); ?>> <?php esc_html_e( 'Display the review date', 'elplan-kuchikomi-wall' ); ?></label></td>
                            </tr>
                            <tr>
                                <th><?php esc_html_e( 'Show Source Badge', 'elplan-kuchikomi-wall' ); ?></th>
                                <td><label><input type="checkbox" id="tmnl-show-source" value="1" <?php checked( get_option( 'tmnl_show_source', 1 ), 1 ); ?>> <?php esc_html_e( 'Display the source label', 'elplan-kuchikomi-wall' ); ?></label></td>
                            </tr>
                            <tr>
                                <th><?php esc_html_e( 'Expand Long Reviews', 'elplan-kuchikomi-wall' ); ?></th>
                                <td><label><input type="checkbox" id="tmnl-expand-text" value="1" <?php checked( get_option( 'tmnl_expand_text', 0 ), 1 ); ?>> <?php esc_html_e( 'Truncate with "…more" toggle', 'elplan-kuchikomi-wall' ); ?></label></td>
                            </tr>
                        </table>

                        <div class="tmnl-form-actions">
                            <button type="button" class="button button-primary" id="tmnl-save-display"><?php esc_html_e( 'Save Settings', 'elplan-kuchikomi-wall' ); ?></button>
                        </div>
                    </div>

                    <div class="tmnl-display-preview">
                        <div class="tmnl-preview-label"><?php esc_html_e( 'Live Preview', 'elplan-kuchikomi-wall' ); ?></div>
                        <div id="tmnl-display-preview-area" class="tmnl-preview-area">
                            <span class="tmnl-preview-loading"><?php esc_html_e( 'Loading preview…', 'elplan-kuchikomi-wall' ); ?></span>
                        </div>
                    </div>
                </div>
            </div>
        </div>
        <?php
    }

    // =========================================
    // Section: Shortcode
    // =========================================

    private function render_shortcode_section() {
        $locale        = get_locale();
        $api_guide_url = ( 'ja' === substr( $locale, 0, 2 ) )
            ? 'https://www.el-plan.com/kuchikomi-wall/api-guide/'
            : 'https://www.el-plan.com/kuchikomi-wall/api-guide-en/';
        ?>
        <div class="tmnl-section" id="tmnl-section-shortcode">
            <div class="tmnl-section-header">
                <span class="dashicons dashicons-shortcode tmnl-section-icon"></span>
                <h2 class="tmnl-section-title"><?php esc_html_e( 'Shortcode', 'elplan-kuchikomi-wall' ); ?></h2>
            </div>
            <div class="tmnl-section-body">
                <p><?php esc_html_e( 'Paste this shortcode into any page or post:', 'elplan-kuchikomi-wall' ); ?></p>
                <div class="tmnl-shortcode-copy-box">
                    <code id="tmnl-main-shortcode">[tmnl_kuchikomi_wall]</code>
                    <button type="button" class="button" id="tmnl-copy-shortcode-main"><?php esc_html_e( 'Copy', 'elplan-kuchikomi-wall' ); ?></button>
                </div>
                <details style="margin-top:16px;">
                    <summary style="cursor:pointer;color:#2271b1;"><?php esc_html_e( 'Available parameters', 'elplan-kuchikomi-wall' ); ?></summary>
                    <table class="widefat" style="max-width:640px;margin-top:8px;">
                        <thead><tr>
                            <th><?php esc_html_e( 'Parameter', 'elplan-kuchikomi-wall' ); ?></th>
                            <th><?php esc_html_e( 'Values', 'elplan-kuchikomi-wall' ); ?></th>
                            <th><?php esc_html_e( 'Description', 'elplan-kuchikomi-wall' ); ?></th>
                        </tr></thead>
                        <tbody>
                            <tr><td><code>template</code></td><td>card / slider / list / badge / floating</td><td><?php esc_html_e( 'Display template', 'elplan-kuchikomi-wall' ); ?></td></tr>
                            <tr><td><code>color</code></td><td>light / dark / auto</td><td><?php esc_html_e( 'Color scheme', 'elplan-kuchikomi-wall' ); ?></td></tr>
                            <tr><td><code>columns</code></td><td>1–4</td><td><?php esc_html_e( 'Columns (card only)', 'elplan-kuchikomi-wall' ); ?></td></tr>
                            <tr><td><code>limit</code></td><td><?php esc_html_e( 'number', 'elplan-kuchikomi-wall' ); ?></td><td><?php esc_html_e( 'Max reviews', 'elplan-kuchikomi-wall' ); ?></td></tr>
                            <tr><td><code>source</code></td><td>all / manual / google / x_embed</td><td><?php esc_html_e( 'Filter by source', 'elplan-kuchikomi-wall' ); ?></td></tr>
                            <tr><td><code>min_rating</code></td><td>1–5</td><td><?php esc_html_e( 'Minimum star rating', 'elplan-kuchikomi-wall' ); ?></td></tr>
                            <tr><td><code>show_photo</code></td><td>0 / 1</td><td><?php esc_html_e( 'Show author photo', 'elplan-kuchikomi-wall' ); ?></td></tr>
                            <tr><td><code>show_date</code></td><td>0 / 1</td><td><?php esc_html_e( 'Show review date', 'elplan-kuchikomi-wall' ); ?></td></tr>
                            <tr><td><code>show_source</code></td><td>0 / 1</td><td><?php esc_html_e( 'Show source badge', 'elplan-kuchikomi-wall' ); ?></td></tr>
                            <tr><td><code>expand_text</code></td><td>0 / 1</td><td><?php esc_html_e( 'Collapse long reviews', 'elplan-kuchikomi-wall' ); ?></td></tr>
                        </tbody>
                    </table>
                </details>
                <p style="margin-top:16px;">
                    <a href="<?php echo esc_url( admin_url( 'admin.php?page=tmnl-setup' ) ); ?>" class="button">
                        <span class="dashicons dashicons-welcome-learn-more" style="margin-top:3px"></span>
                        <?php esc_html_e( 'Setup Wizard', 'elplan-kuchikomi-wall' ); ?>
                    </a>
                    <a href="<?php echo esc_url( $api_guide_url ); ?>" target="_blank" rel="noopener noreferrer" class="button" style="margin-left:8px;">
                        <span class="dashicons dashicons-external" style="margin-top:3px"></span>
                        <?php esc_html_e( 'API Key Guide', 'elplan-kuchikomi-wall' ); ?>
                    </a>
                    <a href="https://www.el-plan.com/kuchikomi-wall/" target="_blank" rel="noopener noreferrer" class="button" style="margin-left:8px;">
                        <?php esc_html_e( 'Documentation', 'elplan-kuchikomi-wall' ); ?>
                    </a>
                </p>
            </div>
        </div>
        <?php
    }

    // =========================================
    // Section: Upgrade banner
    // =========================================

    private function render_upgrade_banner() {
        if ( kw_is_pro() ) return;
        ?>
        <div class="tmnl-upgrade-banner">
            <div class="tmnl-upgrade-banner-inner">
                <div class="tmnl-upgrade-banner-text">
                    <strong>&#11088; <?php esc_html_e( 'Upgrade to Pro', 'elplan-kuchikomi-wall' ); ?></strong>
                    <span><?php esc_html_e( 'Unlock Schema.org structured data output, multiple locations, QR codes, and more.', 'elplan-kuchikomi-wall' ); ?></span>
                </div>
                <div class="tmnl-upgrade-banner-actions">
                    <button type="button" id="tmnl-upgrade-btn" class="button button-primary tmnl-upgrade-button">
                        <?php esc_html_e( 'Upgrade to Pro &rarr;', 'elplan-kuchikomi-wall' ); ?>
                    </button>
                    <a href="https://www.el-plan.com/kuchikomi-wall/#pricing" target="_blank" rel="noopener noreferrer" class="tmnl-upgrade-learnmore">
                        <?php esc_html_e( 'See pricing', 'elplan-kuchikomi-wall' ); ?>
                    </a>
                </div>
            </div>
            <div class="tmnl-compare-table-wrap">
                <table class="tmnl-compare-table">
                    <thead><tr>
                        <th><?php esc_html_e( 'Feature', 'elplan-kuchikomi-wall' ); ?></th>
                        <th><?php esc_html_e( 'Free', 'elplan-kuchikomi-wall' ); ?></th>
                        <th><?php esc_html_e( 'Pro', 'elplan-kuchikomi-wall' ); ?></th>
                    </tr></thead>
                    <tbody>
                        <tr><td><?php esc_html_e( 'Manual testimonials', 'elplan-kuchikomi-wall' ); ?></td><td class="tmnl-yes">&#10003;</td><td class="tmnl-yes">&#10003;</td></tr>
                        <tr><td><?php esc_html_e( 'Google Reviews (1 location)', 'elplan-kuchikomi-wall' ); ?></td><td class="tmnl-yes">&#10003;</td><td class="tmnl-yes">&#10003;</td></tr>
                        <tr><td><?php esc_html_e( 'X (Twitter) embeds', 'elplan-kuchikomi-wall' ); ?></td><td class="tmnl-yes">&#10003;</td><td class="tmnl-yes">&#10003;</td></tr>
                        <tr><td><?php esc_html_e( '5 display templates', 'elplan-kuchikomi-wall' ); ?></td><td class="tmnl-yes">&#10003;</td><td class="tmnl-yes">&#10003;</td></tr>
                        <tr class="tmnl-pro-row"><td><?php esc_html_e( 'Multiple locations', 'elplan-kuchikomi-wall' ); ?></td><td class="tmnl-no">&#8212;</td><td class="tmnl-yes">&#10003;</td></tr>
                        <tr class="tmnl-pro-row"><td><?php esc_html_e( 'Schema.org JSON-LD', 'elplan-kuchikomi-wall' ); ?></td><td class="tmnl-no">&#8212;</td><td class="tmnl-yes">&#10003;</td></tr>
                        <tr class="tmnl-pro-row"><td><?php esc_html_e( 'Review request QR code', 'elplan-kuchikomi-wall' ); ?></td><td class="tmnl-no">&#8212;</td><td class="tmnl-yes">&#10003;</td></tr>
                    </tbody>
                </table>
            </div>
        </div>
        <script type="text/javascript" src="https://checkout.freemius.com/js/v1/"></script>
        <script type="text/javascript">
        jQuery(function($){
            var handler = new FS.Checkout({
                product_id : '26100', plan_id: '43143',
                public_key : 'pk_21a37720e14df2112646e173c6fb0',
                image      : 'https://www.el-plan.com/kuchikomi-wall/assets/icon-128x128.png'
            });
            $('#tmnl-upgrade-btn').on('click', function(e){
                e.preventDefault();
                handler.open({ name: 'Kuchikomi Wall Pro', licenses: 1 });
            });
        });
        </script>
        <?php
    }

    // =========================================
    // Scripts
    // =========================================

    private function render_scripts( $nonces ) {
        $i18n = array(
            'saving'         => __( 'Saving…',           'elplan-kuchikomi-wall' ),
            'saved'          => __( 'Saved!',             'elplan-kuchikomi-wall' ),
            'error'          => __( 'Error',              'elplan-kuchikomi-wall' ),
            'testing'        => __( 'Testing…',           'elplan-kuchikomi-wall' ),
            'fetching'       => __( 'Fetching…',          'elplan-kuchikomi-wall' ),
            'adding'         => __( 'Adding…',            'elplan-kuchikomi-wall' ),
            'save_settings'  => __( 'Save Settings',      'elplan-kuchikomi-wall' ),
            'save'           => __( 'Save',               'elplan-kuchikomi-wall' ),
            'add_tweet'      => __( 'Add Tweet',          'elplan-kuchikomi-wall' ),
            'fetch_reviews'  => __( 'Fetch Reviews Now',  'elplan-kuchikomi-wall' ),
            'test'           => __( 'Test',               'elplan-kuchikomi-wall' ),
            'copy'           => __( 'Copy',               'elplan-kuchikomi-wall' ),
            'copied'         => __( 'Copied!',            'elplan-kuchikomi-wall' ),
            'test_ok'        => __( '✓ Connection successful!', 'elplan-kuchikomi-wall' ),
            'confirm_delete' => __( 'Are you sure?',      'elplan-kuchikomi-wall' ),
            'add_label'      => __( 'Add Testimonial',    'elplan-kuchikomi-wall' ),
            'edit_label'     => __( 'Edit Testimonial',   'elplan-kuchikomi-wall' ),
            'saved_ok'       => __( 'Settings saved.',    'elplan-kuchikomi-wall' ),
            'display_saved'  => __( 'Display settings saved.', 'elplan-kuchikomi-wall' ),
            'reviews_fetched'=> __( 'Reviews fetched!',   'elplan-kuchikomi-wall' ),
            'deleted'        => __( 'Deleted.',           'elplan-kuchikomi-wall' ),
            'tweet_added'    => __( 'Tweet added.',        'elplan-kuchikomi-wall' ),
            'preview_loading'=> __( 'Loading preview…',   'elplan-kuchikomi-wall' ),
            'author_required'=> __( 'Author and content are required.', 'elplan-kuchikomi-wall' ),
        );
        $data = wp_json_encode( array(
            'ajaxurl' => admin_url( 'admin-ajax.php' ),
            'nonces'  => $nonces,
            'i18n'    => $i18n,
        ) );
        ?>
        <script type="text/javascript">
        (function($){
            var tmnl = <?php echo $data; // phpcs:ignore WordPress.Security.EscapeOutput ?>;

            function showNotice(type, msg) {
                var $n = $('<div class="notice notice-' + type + ' is-dismissible tmnl-inline-notice"><p>' + msg + '</p></div>');
                $('#tmnl-notice-area').html($n);
                setTimeout(function(){ $n.fadeOut(400, function(){ $(this).remove(); }); }, 4000);
            }

            // Accordion
            $(document).on('click', '.tmnl-accordion-trigger', function(e){
                if ($(e.target).is('button, a, input, select, textarea')) return;
                var $sec  = $(this).closest('.tmnl-section');
                var $body = $sec.find('> .tmnl-section-body').first();
                $body.slideToggle(200);
                $sec.toggleClass('tmnl-section-collapsed');
                $(this).find('.tmnl-accordion-arrow').toggleClass('tmnl-arrow-open');
            });

            // ── Google: Test ──────────────────────────────────
            $('#tmnl-test-api-key').on('click', function(){
                var key = $('#tmnl-google-api-key').val().trim();
                if (!key) return;
                var $btn = $(this).prop('disabled', true).text(tmnl.i18n.testing);
                $('#tmnl-api-key-result').html('');
                $.post(tmnl.ajaxurl, { action: 'tmnl_test_api_key', api_key: key, _ajax_nonce: tmnl.nonces.test_api_key }, function(res){
                    $btn.prop('disabled', false).text(tmnl.i18n.test);
                    if (res.success) {
                        $('#tmnl-api-key-result').html('<span style="color:#2e7d32;">' + tmnl.i18n.test_ok + '</span>');
                    } else {
                        $('#tmnl-api-key-result').html('<span style="color:#b91c1c;">✗ ' + (res.data || tmnl.i18n.error) + '</span>');
                    }
                });
            });

            // ── Google: Save ──────────────────────────────────
            $('#tmnl-save-google').on('click', function(){
                var $btn = $(this).prop('disabled', true).text(tmnl.i18n.saving);
                $.post(tmnl.ajaxurl, {
                    action: 'tmnl_save_google',
                    api_key:  $('#tmnl-google-api-key').val().trim(),
                    place_id: $('#tmnl-google-place-id').val().trim(),
                    _ajax_nonce: tmnl.nonces.save_google
                }, function(res){
                    $btn.prop('disabled', false).text(tmnl.i18n.save_settings);
                    if (res.success) showNotice('success', tmnl.i18n.saved_ok);
                    else showNotice('error', res.data || tmnl.i18n.error);
                });
            });

            // ── Google: Fetch ─────────────────────────────────
            $('#tmnl-fetch-google').on('click', function(){
                var $btn = $(this).prop('disabled', true).text(tmnl.i18n.fetching);
                $('#tmnl-google-fetch-result').html('');
                $.post(tmnl.ajaxurl, { action: 'tmnl_fetch_google', _ajax_nonce: tmnl.nonces.fetch_google }, function(res){
                    $btn.prop('disabled', false).text(tmnl.i18n.fetch_reviews);
                    if (res.success) {
                        showNotice('success', tmnl.i18n.reviews_fetched);
                        if (res.data && res.data.reviews_html) {
                            $('#tmnl-google-reviews-wrap').html(res.data.reviews_html);
                        }
                    } else {
                        showNotice('error', res.data || tmnl.i18n.error);
                    }
                });
            });

            // ── Display: Live preview ─────────────────────────
            var previewTimer;
            function updatePreview() {
                clearTimeout(previewTimer);
                previewTimer = setTimeout(function(){
                    var tpl = $('input[name="tmnl_template"]:checked').val() || 'card';
                    $('#tmnl-display-preview-area').html('<span class="tmnl-preview-loading">' + tmnl.i18n.preview_loading + '</span>');
                    $.post(tmnl.ajaxurl, {
                        action: 'tmnl_live_preview',
                        template: tpl,
                        color:    $('#tmnl-color-scheme').val(),
                        columns:  $('#tmnl-columns').val() || 3,
                        limit:    3,
                        _ajax_nonce: tmnl.nonces.live_preview
                    }, function(res){
                        if (res.success) $('#tmnl-display-preview-area').html(res.data.html);
                    });
                }, 350);
            }

            $(document).on('change', 'input[name="tmnl_template"]', function(){
                $('.tmnl-tpl-option').removeClass('tmnl-tpl-active');
                $(this).closest('.tmnl-tpl-option').addClass('tmnl-tpl-active');
                $('#tmnl-columns-row').toggle($(this).val() === 'card');
                updatePreview();
            });
            $('#tmnl-color-scheme, #tmnl-columns').on('change', updatePreview);
            updatePreview();

            // ── Display: Save ─────────────────────────────────
            $('#tmnl-save-display').on('click', function(){
                var $btn = $(this).prop('disabled', true).text(tmnl.i18n.saving);
                $.post(tmnl.ajaxurl, {
                    action:        'tmnl_save_display',
                    template:      $('input[name="tmnl_template"]:checked').val(),
                    color_scheme:  $('#tmnl-color-scheme').val(),
                    columns:       $('#tmnl-columns').val(),
                    min_rating:    $('#tmnl-min-rating').val(),
                    default_limit: $('#tmnl-default-limit').val(),
                    show_photo:    $('#tmnl-show-photo').is(':checked') ? 1 : 0,
                    show_date:     $('#tmnl-show-date').is(':checked') ? 1 : 0,
                    show_source:   $('#tmnl-show-source').is(':checked') ? 1 : 0,
                    expand_text:   $('#tmnl-expand-text').is(':checked') ? 1 : 0,
                    _ajax_nonce:   tmnl.nonces.save_display
                }, function(res){
                    $btn.prop('disabled', false).text(tmnl.i18n.save_settings);
                    if (res.success) showNotice('success', tmnl.i18n.display_saved);
                    else showNotice('error', res.data || tmnl.i18n.error);
                });
            });

            // ── Shortcode: Copy ───────────────────────────────
            $('#tmnl-copy-shortcode-main').on('click', function(){
                navigator.clipboard.writeText($('#tmnl-main-shortcode').text());
                var $btn = $(this).text(tmnl.i18n.copied);
                setTimeout(function(){ $btn.text(tmnl.i18n.copy); }, 2000);
            });

            // ── Manual: Add form ──────────────────────────────
            function resetManualForm() {
                $('#tmnl-manual-id').val('');
                $('#tmnl-m-author').val('');
                $('#tmnl-m-rating').val('5');
                $('#tmnl-m-text').val('');
                $('#tmnl-m-date').val(new Date().toISOString().slice(0, 10));
                $('#tmnl-m-source').val('');
                $('#tmnl-m-visible').prop('checked', true);
            }

            $('#tmnl-manual-add-btn').on('click', function(){
                resetManualForm();
                $('#tmnl-manual-form-title').text(tmnl.i18n.add_label);
                $('#tmnl-manual-form-wrap').slideDown(200);
                $('#tmnl-m-author').focus();
            });

            $('#tmnl-manual-cancel').on('click', function(){
                $('#tmnl-manual-form-wrap').slideUp(200);
            });

            $(document).on('click', '.tmnl-edit-testimonial', function(){
                var d = $(this).data();
                $('#tmnl-manual-id').val(d.id);
                $('#tmnl-m-author').val(d.author);
                $('#tmnl-m-rating').val(d.rating);
                $('#tmnl-m-text').val(d.text);
                $('#tmnl-m-date').val(d.date || '');
                $('#tmnl-m-source').val(d.source || '');
                $('#tmnl-m-visible').prop('checked', parseInt(d.visible, 10) === 1);
                $('#tmnl-manual-form-title').text(tmnl.i18n.edit_label);
                $('#tmnl-manual-form-wrap').slideDown(200);
                $('#tmnl-m-author').focus();
            });

            $('#tmnl-manual-save').on('click', function(){
                var author = $('#tmnl-m-author').val().trim();
                var text   = $('#tmnl-m-text').val().trim();
                if (!author || !text) { alert(tmnl.i18n.author_required); return; }
                var $btn = $(this).prop('disabled', true).text(tmnl.i18n.saving);
                $.post(tmnl.ajaxurl, {
                    action:       'tmnl_save_testimonial',
                    id:           $('#tmnl-manual-id').val(),
                    author_name:  author,
                    rating:       $('#tmnl-m-rating').val(),
                    text:         text,
                    review_date:  $('#tmnl-m-date').val(),
                    source_label: $('#tmnl-m-source').val(),
                    is_visible:   $('#tmnl-m-visible').is(':checked') ? 1 : 0,
                    _ajax_nonce:  tmnl.nonces.save_testimonial
                }, function(res){
                    $btn.prop('disabled', false).text(tmnl.i18n.save);
                    if (res.success) {
                        showNotice('success', res.data.message);
                        $('#tmnl-manual-list').html(res.data.html);
                        $('#tmnl-manual-form-wrap').slideUp(200);
                        resetManualForm();
                    } else {
                        showNotice('error', res.data || tmnl.i18n.error);
                    }
                });
            });

            $(document).on('click', '.tmnl-toggle-testimonial', function(){
                var id = $(this).data('id');
                $.post(tmnl.ajaxurl, { action: 'tmnl_toggle_testimonial', id: id, _ajax_nonce: tmnl.nonces.toggle_testimonial }, function(res){
                    if (res.success) $('#tmnl-manual-list').html(res.data.html);
                    else showNotice('error', res.data || tmnl.i18n.error);
                });
            });

            $(document).on('click', '.tmnl-delete-testimonial', function(){
                if (!confirm(tmnl.i18n.confirm_delete)) return;
                var id = $(this).data('id');
                $.post(tmnl.ajaxurl, { action: 'tmnl_delete_testimonial', id: id, _ajax_nonce: tmnl.nonces.delete_testimonial }, function(res){
                    if (res.success) { showNotice('success', tmnl.i18n.deleted); $('#tmnl-manual-list').html(res.data.html); }
                    else showNotice('error', res.data || tmnl.i18n.error);
                });
            });

            // ── X Embeds ──────────────────────────────────────
            $('#tmnl-add-x-embed').on('click', function(){
                var url = $('#tmnl-x-url').val().trim();
                if (!url) return;
                var $btn = $(this).prop('disabled', true).text(tmnl.i18n.adding);
                $('#tmnl-x-result').html('');
                $.post(tmnl.ajaxurl, { action: 'tmnl_add_x_embed', tweet_url: url, _ajax_nonce: tmnl.nonces.add_x_embed }, function(res){
                    $btn.prop('disabled', false).text(tmnl.i18n.add_tweet);
                    if (res.success) {
                        showNotice('success', tmnl.i18n.tweet_added);
                        $('#tmnl-x-url').val('');
                        $('#tmnl-x-list').html(res.data.html);
                    } else {
                        $('#tmnl-x-result').html('<span style="color:#b91c1c;">✗ ' + (res.data || tmnl.i18n.error) + '</span>');
                    }
                });
            });

            $(document).on('click', '.tmnl-toggle-x-embed', function(){
                var id = $(this).data('id');
                $.post(tmnl.ajaxurl, { action: 'tmnl_toggle_x_embed', id: id, _ajax_nonce: tmnl.nonces.toggle_x_embed }, function(res){
                    if (res.success) $('#tmnl-x-list').html(res.data.html);
                    else showNotice('error', res.data || tmnl.i18n.error);
                });
            });

            $(document).on('click', '.tmnl-delete-x-embed', function(){
                if (!confirm(tmnl.i18n.confirm_delete)) return;
                var id = $(this).data('id');
                $.post(tmnl.ajaxurl, { action: 'tmnl_delete_x_embed', id: id, _ajax_nonce: tmnl.nonces.delete_x_embed }, function(res){
                    if (res.success) { showNotice('success', tmnl.i18n.deleted); $('#tmnl-x-list').html(res.data.html); }
                    else showNotice('error', res.data || tmnl.i18n.error);
                });
            });

        })(jQuery);
        </script>
        <?php
    }

    // =========================================
    // Setup Wizard (hidden page — unchanged)
    // =========================================

    public function page_wizard() {
        $google_adapter = $this->get_adapter( 'google' );
        $saved_api_key  = '';
        $saved_place_id = '';
        if ( $google_adapter ) {
            $settings       = get_option( 'tmnl_source_google', array() );
            $saved_api_key  = $settings['api_key']  ?? '';
            $saved_place_id = $settings['place_id'] ?? '';
        }

        $locale        = get_locale();
        $api_guide_url = ( 'ja' === substr( $locale, 0, 2 ) )
            ? 'https://www.el-plan.com/kuchikomi-wall/api-guide/'
            : 'https://www.el-plan.com/kuchikomi-wall/api-guide-en/';
        ?>
        <div class="wrap tmnl-wrap">
            <h1><?php esc_html_e( 'Setup Wizard', 'elplan-kuchikomi-wall' ); ?></h1>
            <p class="description"><?php esc_html_e( 'Connect Google Reviews and choose your display style in 3 steps.', 'elplan-kuchikomi-wall' ); ?></p>

            <div class="tmnl-wizard-steps">
                <div class="tmnl-wizard-step-item tmnl-step-active" data-step="1">
                    <span class="tmnl-step-num">1</span>
                    <span class="tmnl-step-label"><?php esc_html_e( 'API Key', 'elplan-kuchikomi-wall' ); ?></span>
                </div>
                <div class="tmnl-wizard-step-sep"></div>
                <div class="tmnl-wizard-step-item" data-step="2">
                    <span class="tmnl-step-num">2</span>
                    <span class="tmnl-step-label"><?php esc_html_e( 'Location', 'elplan-kuchikomi-wall' ); ?></span>
                </div>
                <div class="tmnl-wizard-step-sep"></div>
                <div class="tmnl-wizard-step-item" data-step="3">
                    <span class="tmnl-step-num">3</span>
                    <span class="tmnl-step-label"><?php esc_html_e( 'Design', 'elplan-kuchikomi-wall' ); ?></span>
                </div>
            </div>

            <div class="tmnl-wizard-panel" id="tmnl-wizard-step-1">
                <h2><?php esc_html_e( 'Step 1: Connect Google Reviews', 'elplan-kuchikomi-wall' ); ?></h2>
                <p><?php esc_html_e( 'Enter your Google Places API key to fetch your Google reviews automatically.', 'elplan-kuchikomi-wall' ); ?></p>
                <table class="form-table" style="max-width:600px">
                    <tr>
                        <th><label for="tmnl-wiz-api-key"><?php esc_html_e( 'API Key', 'elplan-kuchikomi-wall' ); ?></label></th>
                        <td>
                            <input type="password" id="tmnl-wiz-api-key" class="regular-text"
                                value="<?php echo esc_attr( $saved_api_key ); ?>" placeholder="AIza...">
                            <a href="<?php echo esc_url( $api_guide_url ); ?>" target="_blank" rel="noopener noreferrer" class="button" style="margin-left:8px;">
                                <?php esc_html_e( 'How to get a key →', 'elplan-kuchikomi-wall' ); ?>
                            </a>
                            <br><span id="tmnl-wiz-api-result" style="margin-top:8px;display:inline-block;"></span>
                        </td>
                    </tr>
                </table>
                <div class="tmnl-wizard-nav">
                    <button type="button" class="button" id="tmnl-wiz-test-key"><?php esc_html_e( 'Test Connection', 'elplan-kuchikomi-wall' ); ?></button>
                    <button type="button" class="button button-primary" id="tmnl-wiz-next-1" style="margin-left:12px;"><?php esc_html_e( 'Save & Next →', 'elplan-kuchikomi-wall' ); ?></button>
                </div>
            </div>

            <div class="tmnl-wizard-panel" id="tmnl-wizard-step-2" style="display:none;">
                <h2><?php esc_html_e( 'Step 2: Find Your Location', 'elplan-kuchikomi-wall' ); ?></h2>
                <p><?php esc_html_e( 'Enter the Google Place ID of your business to import your reviews.', 'elplan-kuchikomi-wall' ); ?></p>
                <table class="form-table" style="max-width:600px">
                    <tr>
                        <th><label for="tmnl-wiz-place-id"><?php esc_html_e( 'Place ID', 'elplan-kuchikomi-wall' ); ?></label></th>
                        <td>
                            <input type="text" id="tmnl-wiz-place-id" class="regular-text"
                                value="<?php echo esc_attr( $saved_place_id ); ?>" placeholder="ChIJ...">
                            <p class="description">
                                <a href="https://developers.google.com/maps/documentation/javascript/examples/places-placeid-finder" target="_blank" rel="noopener noreferrer">
                                    <?php esc_html_e( 'Find your Place ID →', 'elplan-kuchikomi-wall' ); ?>
                                </a>
                            </p>
                            <div id="tmnl-wiz-place-info" style="display:none;margin-top:8px;" class="tmnl-cache-info"></div>
                        </td>
                    </tr>
                </table>
                <div class="tmnl-wizard-nav">
                    <button type="button" class="button tmnl-wiz-back" data-target="1"><?php esc_html_e( '← Back', 'elplan-kuchikomi-wall' ); ?></button>
                    <button type="button" class="button" id="tmnl-wiz-fetch-reviews" style="margin-left:8px;"><?php esc_html_e( 'Fetch Reviews', 'elplan-kuchikomi-wall' ); ?></button>
                    <button type="button" class="button button-primary" id="tmnl-wiz-next-2" style="margin-left:8px;"><?php esc_html_e( 'Save & Next →', 'elplan-kuchikomi-wall' ); ?></button>
                </div>
            </div>

            <div class="tmnl-wizard-panel" id="tmnl-wizard-step-3" style="display:none;">
                <h2><?php esc_html_e( 'Step 3: Choose Your Display Style', 'elplan-kuchikomi-wall' ); ?></h2>
                <p><?php esc_html_e( 'Select a template and color scheme. You can preview the result in real time.', 'elplan-kuchikomi-wall' ); ?></p>
                <div class="tmnl-wizard-design-row">
                    <div class="tmnl-wizard-design-controls">
                        <table class="form-table">
                            <tr>
                                <th><?php esc_html_e( 'Template', 'elplan-kuchikomi-wall' ); ?></th>
                                <td>
                                    <div class="tmnl-template-picker" id="tmnl-wiz-template">
                                        <?php
                                        $templates   = array(
                                            'card'     => __( 'Card Grid', 'elplan-kuchikomi-wall' ),
                                            'slider'   => __( 'Slider', 'elplan-kuchikomi-wall' ),
                                            'list'     => __( 'Simple List', 'elplan-kuchikomi-wall' ),
                                            'badge'    => __( 'Badge', 'elplan-kuchikomi-wall' ),
                                            'floating' => __( 'Floating', 'elplan-kuchikomi-wall' ),
                                        );
                                        $current_tpl = get_option( 'tmnl_template', 'card' );
                                        foreach ( $templates as $val => $label ) :
                                        ?>
                                        <label class="tmnl-tpl-option <?php echo $val === $current_tpl ? 'tmnl-tpl-active' : ''; ?>">
                                            <input type="radio" name="wiz_template" value="<?php echo esc_attr( $val ); ?>"
                                                <?php checked( $val, $current_tpl ); ?> style="display:none;">
                                            <span class="tmnl-tpl-icon tmnl-tpl-icon-<?php echo esc_attr( $val ); ?>"></span>
                                            <span><?php echo esc_html( $label ); ?></span>
                                        </label>
                                        <?php endforeach; ?>
                                    </div>
                                </td>
                            </tr>
                            <tr>
                                <th><?php esc_html_e( 'Color Scheme', 'elplan-kuchikomi-wall' ); ?></th>
                                <td>
                                    <select id="tmnl-wiz-color">
                                        <option value="light" <?php selected( get_option( 'tmnl_color_scheme', 'light' ), 'light' ); ?>><?php esc_html_e( 'Light', 'elplan-kuchikomi-wall' ); ?></option>
                                        <option value="dark"  <?php selected( get_option( 'tmnl_color_scheme', 'light' ), 'dark' ); ?>><?php esc_html_e( 'Dark', 'elplan-kuchikomi-wall' ); ?></option>
                                        <option value="auto"  <?php selected( get_option( 'tmnl_color_scheme', 'light' ), 'auto' ); ?>><?php esc_html_e( 'Auto', 'elplan-kuchikomi-wall' ); ?></option>
                                    </select>
                                </td>
                            </tr>
                            <tr id="tmnl-wiz-columns-row">
                                <th><?php esc_html_e( 'Columns', 'elplan-kuchikomi-wall' ); ?></th>
                                <td>
                                    <select id="tmnl-wiz-columns">
                                        <?php for ( $c = 1; $c <= 4; $c++ ) : ?>
                                        <option value="<?php echo esc_attr( $c ); ?>" <?php selected( 3, $c ); ?>><?php echo esc_html( $c ); ?></option>
                                        <?php endfor; ?>
                                    </select>
                                </td>
                            </tr>
                        </table>
                    </div>
                    <div class="tmnl-wizard-preview-pane">
                        <div class="tmnl-preview-label"><?php esc_html_e( 'Preview', 'elplan-kuchikomi-wall' ); ?></div>
                        <div id="tmnl-wiz-preview-area" class="tmnl-preview-area">
                            <span class="tmnl-preview-loading"><?php esc_html_e( 'Loading preview…', 'elplan-kuchikomi-wall' ); ?></span>
                        </div>
                    </div>
                </div>
                <div class="tmnl-wizard-nav" style="margin-top:24px;">
                    <button type="button" class="button tmnl-wiz-back" data-target="2"><?php esc_html_e( '← Back', 'elplan-kuchikomi-wall' ); ?></button>
                    <button type="button" class="button button-primary" id="tmnl-wiz-finish" style="margin-left:12px;"><?php esc_html_e( 'Save & Finish →', 'elplan-kuchikomi-wall' ); ?></button>
                </div>
            </div>

            <div class="tmnl-wizard-panel" id="tmnl-wizard-step-4" style="display:none;">
                <div class="tmnl-wizard-done">
                    <span class="dashicons dashicons-yes-alt tmnl-done-icon"></span>
                    <h2><?php esc_html_e( 'Setup Complete!', 'elplan-kuchikomi-wall' ); ?></h2>
                    <p><?php esc_html_e( 'Copy the shortcode below and paste it into any page or post.', 'elplan-kuchikomi-wall' ); ?></p>
                    <div class="tmnl-shortcode-copy-box">
                        <code id="tmnl-done-shortcode">[tmnl_kuchikomi_wall]</code>
                        <button type="button" class="button" id="tmnl-copy-shortcode"><?php esc_html_e( 'Copy', 'elplan-kuchikomi-wall' ); ?></button>
                    </div>
                    <p style="margin-top:20px;">
                        <a href="<?php echo esc_url( admin_url( 'admin.php?page=tmnl-dashboard' ) ); ?>" class="button button-primary">
                            <?php esc_html_e( '← Back to Dashboard', 'elplan-kuchikomi-wall' ); ?>
                        </a>
                    </p>
                </div>
            </div>
        </div>

        <script type="text/javascript">
        (function($){
            var currentStep = 1;
            var wizardData  = {
                template: '<?php echo esc_js( get_option( 'tmnl_template', 'card' ) ); ?>',
                color:    '<?php echo esc_js( get_option( 'tmnl_color_scheme', 'light' ) ); ?>',
                columns:  3
            };

            function goStep(n) {
                $('.tmnl-wizard-panel').hide();
                $('#tmnl-wizard-step-' + n).show();
                $('.tmnl-wizard-step-item').removeClass('tmnl-step-active tmnl-step-done');
                for (var i = 1; i < n; i++) {
                    $('[data-step="' + i + '"]').addClass('tmnl-step-done');
                }
                $('[data-step="' + n + '"]').addClass('tmnl-step-active');
                currentStep = n;
                if (n === 3) loadPreview();
            }

            $('#tmnl-wiz-test-key').on('click', function(){
                var key = $('#tmnl-wiz-api-key').val().trim();
                if (!key) { alert('<?php echo esc_js( __( 'Please enter an API key.', 'elplan-kuchikomi-wall' ) ); ?>'); return; }
                var $btn = $(this).prop('disabled', true).text('<?php echo esc_js( __( 'Testing…', 'elplan-kuchikomi-wall' ) ); ?>');
                $.post(ajaxurl, { action: 'tmnl_test_api_key', api_key: key, _ajax_nonce: '<?php echo esc_js( wp_create_nonce( 'tmnl_test_api_key' ) ); ?>' }, function(res){
                    $btn.prop('disabled', false).text('<?php echo esc_js( __( 'Test Connection', 'elplan-kuchikomi-wall' ) ); ?>');
                    if (res.success) {
                        $('#tmnl-wiz-api-result').html('<span style="color:#2e7d32;">&#10003; <?php echo esc_js( __( 'Connection successful!', 'elplan-kuchikomi-wall' ) ); ?></span>');
                    } else {
                        $('#tmnl-wiz-api-result').html('<span style="color:#b91c1c;">&#10007; ' + (res.data || '<?php echo esc_js( __( 'Error', 'elplan-kuchikomi-wall' ) ); ?>') + '</span>');
                    }
                });
            });

            $('#tmnl-wiz-next-1').on('click', function(){
                var key = $('#tmnl-wiz-api-key').val().trim();
                if (!key) { alert('<?php echo esc_js( __( 'Please enter an API key.', 'elplan-kuchikomi-wall' ) ); ?>'); return; }
                $.post(ajaxurl, { action: 'tmnl_wizard_save_step', step: 1, api_key: key, _ajax_nonce: '<?php echo esc_js( wp_create_nonce( 'tmnl_wizard_save_step' ) ); ?>' }, function(){ goStep(2); });
            });

            $('#tmnl-wiz-fetch-reviews').on('click', function(){
                var pid = $('#tmnl-wiz-place-id').val().trim();
                if (!pid) { alert('<?php echo esc_js( __( 'Please enter a Place ID.', 'elplan-kuchikomi-wall' ) ); ?>'); return; }
                var $btn = $(this).prop('disabled', true).text('<?php echo esc_js( __( 'Fetching…', 'elplan-kuchikomi-wall' ) ); ?>');
                $.post(ajaxurl, { action: 'tmnl_wizard_save_step', step: 2, place_id: pid, fetch: 1, _ajax_nonce: '<?php echo esc_js( wp_create_nonce( 'tmnl_wizard_save_step' ) ); ?>' }, function(res){
                    $btn.prop('disabled', false).text('<?php echo esc_js( __( 'Fetch Reviews', 'elplan-kuchikomi-wall' ) ); ?>');
                    if (res.success && res.data && res.data.place_name) {
                        $('#tmnl-wiz-place-info').show().html('<strong>' + res.data.place_name + '</strong> &nbsp;<span style="color:#f5a623;">' + res.data.stars + '</span> ' + res.data.rating + ' / ' + res.data.count + ' reviews');
                    } else {
                        $('#tmnl-wiz-place-info').show().html('<span style="color:#b91c1c;">' + (res.data || '<?php echo esc_js( __( 'Error', 'elplan-kuchikomi-wall' ) ); ?>') + '</span>');
                    }
                });
            });

            $('#tmnl-wiz-next-2').on('click', function(){
                var pid = $('#tmnl-wiz-place-id').val().trim();
                if (!pid) { alert('<?php echo esc_js( __( 'Please enter a Place ID.', 'elplan-kuchikomi-wall' ) ); ?>'); return; }
                $.post(ajaxurl, { action: 'tmnl_wizard_save_step', step: 2, place_id: pid, _ajax_nonce: '<?php echo esc_js( wp_create_nonce( 'tmnl_wizard_save_step' ) ); ?>' }, function(){ goStep(3); });
            });

            $(document).on('change', 'input[name="wiz_template"]', function(){
                wizardData.template = $(this).val();
                $('.tmnl-tpl-option').removeClass('tmnl-tpl-active');
                $(this).closest('.tmnl-tpl-option').addClass('tmnl-tpl-active');
                $('#tmnl-wiz-columns-row').toggle(wizardData.template === 'card');
                loadPreview();
            });
            $('#tmnl-wiz-color').on('change', function(){ wizardData.color = $(this).val(); loadPreview(); });
            $('#tmnl-wiz-columns').on('change', function(){ wizardData.columns = $(this).val(); loadPreview(); });

            var previewTimer;
            function loadPreview() {
                clearTimeout(previewTimer);
                previewTimer = setTimeout(function(){
                    $('#tmnl-wiz-preview-area').html('<span class="tmnl-preview-loading"><?php echo esc_js( __( 'Loading preview…', 'elplan-kuchikomi-wall' ) ); ?></span>');
                    $.post(ajaxurl, { action: 'tmnl_live_preview', template: wizardData.template, color: wizardData.color, columns: wizardData.columns, limit: 3, _ajax_nonce: '<?php echo esc_js( wp_create_nonce( 'tmnl_live_preview' ) ); ?>' }, function(res){
                        if (res.success) $('#tmnl-wiz-preview-area').html(res.data.html);
                    });
                }, 300);
            }

            $('#tmnl-wiz-finish').on('click', function(){
                $.post(ajaxurl, { action: 'tmnl_wizard_save_step', step: 3, template: wizardData.template, color: wizardData.color, columns: wizardData.columns, _ajax_nonce: '<?php echo esc_js( wp_create_nonce( 'tmnl_wizard_save_step' ) ); ?>' }, function(){
                    var sc = '[tmnl_kuchikomi_wall template="' + wizardData.template + '" color="' + wizardData.color + '"';
                    if (wizardData.template === 'card') sc += ' columns="' + wizardData.columns + '"';
                    sc += ']';
                    $('#tmnl-done-shortcode').text(sc);
                    goStep(4);
                });
            });

            $(document).on('click', '.tmnl-wiz-back', function(){ goStep(parseInt($(this).data('target'), 10)); });
            $('#tmnl-copy-shortcode').on('click', function(){
                navigator.clipboard.writeText($('#tmnl-done-shortcode').text());
                $(this).text('<?php echo esc_js( __( 'Copied!', 'elplan-kuchikomi-wall' ) ); ?>');
            });
        })(jQuery);
        </script>
        <?php
    }

    // =========================================
    // AJAX: Google
    // =========================================

    public function ajax_save_google() {
        check_ajax_referer( 'tmnl_save_google' );
        if ( ! current_user_can( 'manage_options' ) ) wp_die();
        $adapter = $this->get_adapter( 'google' );
        if ( ! $adapter ) wp_send_json_error( esc_html__( 'Google adapter not found.', 'elplan-kuchikomi-wall' ) );
        $adapter->save_dashboard_settings(
            wp_unslash( $_POST['api_key'] ?? '' ),
            wp_unslash( $_POST['place_id'] ?? '' )
        );
        wp_send_json_success();
    }

    public function ajax_fetch_google() {
        check_ajax_referer( 'tmnl_fetch_google' );
        if ( ! current_user_can( 'manage_options' ) ) wp_die();
        $adapter = $this->get_adapter( 'google' );
        if ( ! $adapter ) wp_send_json_error( esc_html__( 'Google adapter not found.', 'elplan-kuchikomi-wall' ) );
        $result = $adapter->fetch( true );
        if ( is_wp_error( $result ) ) wp_send_json_error( $result->get_error_message() );
        wp_send_json_success( array( 'reviews_html' => $this->get_google_reviews_html() ) );
    }

    // =========================================
    // AJAX: Display
    // =========================================

    public function ajax_save_display() {
        check_ajax_referer( 'tmnl_save_display' );
        if ( ! current_user_can( 'manage_options' ) ) wp_die();
        update_option( 'tmnl_template',        sanitize_text_field( $_POST['template']      ?? 'card' ) );
        update_option( 'tmnl_color_scheme',    sanitize_text_field( $_POST['color_scheme']  ?? 'light' ) );
        update_option( 'tmnl_default_columns', max( 1, min( 4, intval( $_POST['columns']       ?? 3 ) ) ) );
        update_option( 'tmnl_min_rating',      max( 1, min( 5, intval( $_POST['min_rating']    ?? 1 ) ) ) );
        update_option( 'tmnl_default_limit',   max( 1, min( 50, intval( $_POST['default_limit'] ?? 6 ) ) ) );
        update_option( 'tmnl_show_photo',      intval( $_POST['show_photo']  ?? 0 ) );
        update_option( 'tmnl_show_date',       intval( $_POST['show_date']   ?? 0 ) );
        update_option( 'tmnl_show_source',     intval( $_POST['show_source'] ?? 0 ) );
        update_option( 'tmnl_expand_text',     intval( $_POST['expand_text'] ?? 0 ) );
        wp_send_json_success();
    }

    // =========================================
    // AJAX: Manual testimonials
    // =========================================

    public function ajax_save_testimonial() {
        check_ajax_referer( 'tmnl_save_testimonial' );
        if ( ! current_user_can( 'manage_options' ) ) wp_die();
        $data = array(
            'author_name'  => sanitize_text_field( wp_unslash( $_POST['author_name']  ?? '' ) ),
            'rating'       => max( 1, min( 5, absint( $_POST['rating'] ?? 5 ) ) ),
            'text'         => sanitize_textarea_field( wp_unslash( $_POST['text']         ?? '' ) ),
            'review_date'  => sanitize_text_field( wp_unslash( $_POST['review_date']  ?? '' ) ),
            'source_label' => sanitize_text_field( wp_unslash( $_POST['source_label'] ?? '' ) ),
            'source_type'  => 'manual',
            'is_visible'   => intval( $_POST['is_visible'] ?? 1 ),
            'sort_order'   => 0,
        );
        $id = intval( $_POST['id'] ?? 0 );
        if ( $id ) {
            TMNL_DB::update( $id, $data );
            $message = esc_html__( 'Testimonial updated.', 'elplan-kuchikomi-wall' );
        } else {
            TMNL_DB::insert( $data );
            $message = esc_html__( 'Testimonial added.', 'elplan-kuchikomi-wall' );
        }
        wp_send_json_success( array( 'message' => $message, 'html' => $this->get_testimonials_html() ) );
    }

    public function ajax_delete_testimonial() {
        check_ajax_referer( 'tmnl_delete_testimonial' );
        if ( ! current_user_can( 'manage_options' ) ) wp_die();
        TMNL_DB::delete( intval( $_POST['id'] ?? 0 ) );
        wp_send_json_success( array( 'html' => $this->get_testimonials_html() ) );
    }

    public function ajax_toggle_testimonial() {
        check_ajax_referer( 'tmnl_toggle_testimonial' );
        if ( ! current_user_can( 'manage_options' ) ) wp_die();
        TMNL_DB::toggle_visibility( intval( $_POST['id'] ?? 0 ) );
        wp_send_json_success( array( 'html' => $this->get_testimonials_html() ) );
    }

    // =========================================
    // AJAX: X Embeds
    // =========================================

    public function ajax_add_x_embed() {
        check_ajax_referer( 'tmnl_add_x_embed' );
        if ( ! current_user_can( 'manage_options' ) ) wp_die();
        $adapter = $this->get_adapter( 'x_embed' );
        if ( ! $adapter ) wp_send_json_error( esc_html__( 'X adapter not found.', 'elplan-kuchikomi-wall' ) );
        $result = $adapter->add_tweet( esc_url_raw( wp_unslash( $_POST['tweet_url'] ?? '' ) ) );
        if ( is_wp_error( $result ) ) wp_send_json_error( $result->get_error_message() );
        wp_send_json_success( array( 'html' => $this->get_x_embeds_html() ) );
    }

    public function ajax_delete_x_embed() {
        check_ajax_referer( 'tmnl_delete_x_embed' );
        if ( ! current_user_can( 'manage_options' ) ) wp_die();
        TMNL_DB::delete_x_embed( intval( $_POST['id'] ?? 0 ) );
        wp_send_json_success( array( 'html' => $this->get_x_embeds_html() ) );
    }

    public function ajax_toggle_x_embed() {
        check_ajax_referer( 'tmnl_toggle_x_embed' );
        if ( ! current_user_can( 'manage_options' ) ) wp_die();
        TMNL_DB::toggle_x_embed_visibility( intval( $_POST['id'] ?? 0 ) );
        wp_send_json_success( array( 'html' => $this->get_x_embeds_html() ) );
    }

    // =========================================
    // AJAX: Test API key
    // =========================================

    public function ajax_test_api_key() {
        check_ajax_referer( 'tmnl_test_api_key' );
        if ( ! current_user_can( 'manage_options' ) ) {
            wp_send_json_error( esc_html__( 'Permission denied.', 'elplan-kuchikomi-wall' ) );
        }
        $api_key = sanitize_text_field( wp_unslash( $_POST['api_key'] ?? '' ) );
        if ( empty( $api_key ) ) {
            wp_send_json_error( esc_html__( 'Please enter an API key.', 'elplan-kuchikomi-wall' ) );
        }
        $url      = 'https://places.googleapis.com/v1/places:searchText?key=' . rawurlencode( $api_key );
        $response = wp_remote_post( $url, array(
            'body'    => wp_json_encode( array( 'textQuery' => 'test' ) ),
            'headers' => array( 'Content-Type' => 'application/json' ),
            'timeout' => 10,
        ) );
        if ( is_wp_error( $response ) ) {
            wp_send_json_error( esc_html__( 'Connection error: ', 'elplan-kuchikomi-wall' ) . esc_html( $response->get_error_message() ) );
        }
        $body   = json_decode( wp_remote_retrieve_body( $response ), true );
        $status = $body['error']['status'] ?? '';
        if ( 'REQUEST_DENIED' === $status ) {
            wp_send_json_error( esc_html__( 'API key is invalid or Places API (New) is not enabled.', 'elplan-kuchikomi-wall' ) );
        }
        wp_send_json_success();
    }

    // =========================================
    // AJAX: Live preview
    // =========================================

    public function ajax_live_preview() {
        check_ajax_referer( 'tmnl_live_preview' );
        if ( ! current_user_can( 'manage_options' ) ) wp_die();

        $template = sanitize_text_field( $_POST['template'] ?? 'card' );
        $color    = sanitize_text_field( $_POST['color']    ?? 'light' );
        $columns  = max( 1, min( 4, intval( $_POST['columns'] ?? 3 ) ) );
        $limit    = max( 1, min( 6, intval( $_POST['limit']   ?? 3 ) ) );

        $items = $this->get_preview_items( $limit );
        if ( empty( $items ) ) {
            wp_send_json_success( array( 'html' => '<p style="color:#999;padding:16px;">' . esc_html__( 'No reviews yet. Add some testimonials to see a preview.', 'elplan-kuchikomi-wall' ) . '</p>' ) );
        }

        $sc = new TMNL_Shortcode();
        $sc->set_adapters( $this->adapters );
        $atts = array(
            'limit'       => $limit,
            'template'    => $template,
            'color'       => $color,
            'columns'     => $columns,
            'min_rating'  => 1,
            'show_photo'  => 1,
            'show_date'   => 1,
            'show_source' => 1,
            'expand_text' => 0,
        );
        $html = $sc->render( $atts );
        wp_send_json_success( array( 'html' => $this->get_preview_inline_css() . $html ) );
    }

    private function get_preview_items( $limit ) {
        $items = array();
        foreach ( $this->adapters as $adapter ) {
            $status = $adapter->get_status();
            if ( ! $status['is_enabled'] ) continue;
            $reviews = $adapter->get_normalized_reviews( 1 );
            $items   = array_merge( $items, $reviews );
            if ( count( $items ) >= $limit ) break;
        }
        return array_slice( $items, 0, $limit );
    }

    private function get_preview_inline_css() {
        $css_dir = TMNL_PLUGIN_DIR . 'assets/css/';
        $files   = array( 'tmnl-card.css', 'tmnl-slider.css', 'tmnl-list.css', 'tmnl-badge.css', 'tmnl-floating.css' );
        $out = '<style>';
        foreach ( $files as $f ) {
            $path = $css_dir . $f;
            if ( file_exists( $path ) ) {
                $out .= file_get_contents( $path ); // phpcs:ignore WordPress.WP.AlternativeFunctions.file_get_contents_file_get_contents
            }
        }
        return $out . '</style>';
    }

    // =========================================
    // AJAX: Wizard save step
    // =========================================

    public function ajax_wizard_save_step() {
        check_ajax_referer( 'tmnl_wizard_save_step' );
        if ( ! current_user_can( 'manage_options' ) ) wp_die();

        $step = intval( $_POST['step'] ?? 0 );

        if ( $step === 1 ) {
            $adapter = $this->get_adapter( 'google' );
            if ( ! $adapter ) wp_send_json_error( esc_html__( 'Google adapter not found.', 'elplan-kuchikomi-wall' ) );
            $settings = get_option( 'tmnl_source_google', array() );
            $adapter->save_dashboard_settings(
                wp_unslash( $_POST['api_key'] ?? '' ),
                $settings['place_id'] ?? ''
            );
            wp_send_json_success();
        }

        if ( $step === 2 ) {
            $adapter = $this->get_adapter( 'google' );
            if ( ! $adapter ) wp_send_json_error( esc_html__( 'Google adapter not found.', 'elplan-kuchikomi-wall' ) );
            $settings = get_option( 'tmnl_source_google', array() );
            $adapter->save_dashboard_settings(
                $settings['api_key'] ?? '',
                wp_unslash( $_POST['place_id'] ?? '' )
            );
            if ( ! empty( $_POST['fetch'] ) ) {
                $adapter = $this->get_adapter( 'google' );
                if ( $adapter ) {
                    $result = $adapter->fetch( true );
                    if ( is_wp_error( $result ) ) wp_send_json_error( $result->get_error_message() );
                    $status = $adapter->get_status();
                    wp_send_json_success( array(
                        'place_name' => $status['place_name']   ?? '',
                        'rating'     => $status['place_rating'] ?? '',
                        'count'      => $status['place_count']  ?? '',
                        'stars'      => str_repeat( '★', round( $status['place_rating'] ?? 0 ) ),
                    ) );
                }
            }
            wp_send_json_success();
        }

        if ( $step === 3 ) {
            update_option( 'tmnl_template',        sanitize_text_field( $_POST['template'] ?? 'card' ) );
            update_option( 'tmnl_color_scheme',    sanitize_text_field( $_POST['color']    ?? 'light' ) );
            update_option( 'tmnl_wizard_dismissed', 1 );
            wp_send_json_success();
        }

        wp_send_json_error( 'Unknown step' );
    }

    // =========================================
    // Admin CSS
    // =========================================

    private function get_admin_css() {
        return '
            /* Layout */
            .tmnl-wrap { max-width: 1100px; }
            .tmnl-page-title { display: flex; align-items: center; gap: 8px; margin-bottom: 20px !important; }
            .tmnl-page-title .dashicons { font-size: 28px; width: 28px; height: 28px; color: #2271b1; }

            /* Sections */
            .tmnl-section { background: #fff; border: 1px solid #ccd0d4; border-radius: 6px; margin-bottom: 16px; overflow: hidden; }
            .tmnl-section-header { display: flex; align-items: center; gap: 10px; padding: 14px 20px; border-bottom: 1px solid #ccd0d4; }
            .tmnl-section-collapsed .tmnl-section-header { border-bottom: none; }
            .tmnl-section-collapsed.tmnl-section-body { display: none; }
            .tmnl-accordion-trigger { cursor: pointer; user-select: none; }
            .tmnl-accordion-trigger:hover { background: #f6f7f7; }
            .tmnl-section-icon { font-size: 20px; width: 20px; height: 20px; color: #2271b1; flex-shrink: 0; }
            .tmnl-section-title { margin: 0 !important; font-size: 14px !important; flex: 1; }
            .tmnl-section-meta { font-size: 12px; color: #94a3b8; }
            .tmnl-accordion-arrow { margin-left: auto; color: #94a3b8; transition: transform .2s; flex-shrink: 0; }
            .tmnl-arrow-open { transform: rotate(180deg); }
            .tmnl-section-body { padding: 20px; }

            /* Form rows */
            .tmnl-form-row { display: flex; align-items: flex-start; gap: 12px; margin-bottom: 14px; flex-wrap: wrap; }
            .tmnl-form-label { min-width: 120px; font-weight: 600; font-size: 13px; padding-top: 6px; }
            .tmnl-form-control { display: flex; align-items: center; gap: 8px; flex-wrap: wrap; flex: 1; }
            .tmnl-form-control input.regular-text { flex: 1; min-width: 200px; }
            .tmnl-form-actions { display: flex; align-items: center; gap: 10px; margin-top: 16px; flex-wrap: wrap; }
            .tmnl-form-table th { width: 160px; }
            .tmnl-help-link { font-size: 12px; color: #2271b1; margin-left: 8px; }
            .tmnl-last-updated { font-size: 12px; color: #94a3b8; }
            .tmnl-subsection-title { font-size: 13px !important; font-weight: 600; margin: 0 0 12px !important; color: #1d2327; }
            .tmnl-count { font-weight: 400; color: #94a3b8; }

            /* Notices */
            .tmnl-inline-notice { margin: 0 0 12px !important; }

            /* Lists */
            .tmnl-list-header { margin-bottom: 12px; }
            .tmnl-list-table { margin-top: 12px; }
            .tmnl-row-actions { display: flex; gap: 4px; }
            .tmnl-hidden-row { opacity: 0.5; }
            .tmnl-empty-msg { color: #94a3b8; font-style: italic; }
            .tmnl-mini-meta { font-size: 11px; color: #94a3b8; }

            /* Badges */
            .tmnl-badge { display: inline-block; padding: 2px 8px; border-radius: 3px; font-size: 12px; }
            .tmnl-badge-visible { background: #c6e1c6; color: #2e7d32; }
            .tmnl-badge-hidden  { background: #f5c6cb; color: #721c24; }
            .tmnl-stars { color: #f5a623; }

            /* Google reviews mini cards */
            .tmnl-reviews-grid { margin-top: 16px; }
            .tmnl-mini-cards { display: grid; grid-template-columns: repeat(auto-fill, minmax(180px, 1fr)); gap: 12px; margin-top: 10px; }
            .tmnl-mini-card { border: 1px solid #e2e8f0; border-radius: 6px; padding: 12px; font-size: 12px; background: #fafafa; }
            .tmnl-mini-card-header { display: flex; align-items: center; gap: 8px; margin-bottom: 6px; }
            .tmnl-mini-avatar { width: 28px; height: 28px; border-radius: 50%; object-fit: cover; flex-shrink: 0; }
            .tmnl-mini-text { margin: 0 0 4px; color: #334155; line-height: 1.5; }
            .tmnl-mini-date { color: #94a3b8; font-size: 11px; }

            /* Display settings layout */
            .tmnl-display-layout { display: flex; gap: 32px; align-items: flex-start; flex-wrap: wrap; }
            .tmnl-display-form { flex: 0 0 500px; }
            .tmnl-display-preview { flex: 1; min-width: 280px; position: sticky; top: 32px; }
            .tmnl-preview-label { font-size: 13px; font-weight: 600; color: #50575e; margin-bottom: 8px; }
            .tmnl-preview-area { border: 1px solid #ccd0d4; border-radius: 6px; padding: 12px; background: #f9fafb; min-height: 120px; max-height: 500px; overflow-y: auto; }
            .tmnl-preview-loading { color: #94a3b8; font-size: 13px; }

            /* Template picker */
            .tmnl-template-picker { display: flex; gap: 10px; flex-wrap: wrap; }
            .tmnl-tpl-option { display: flex; flex-direction: column; align-items: center; gap: 6px; padding: 10px 14px; border: 2px solid #e0e0e0; border-radius: 6px; cursor: pointer; font-size: 12px; transition: border-color .15s; min-width: 68px; text-align: center; }
            .tmnl-tpl-option:hover { border-color: #2271b1; }
            .tmnl-tpl-active { border-color: #2271b1; background: #f0f6fc; }
            .tmnl-tpl-icon { width: 36px; height: 28px; border: 1px solid #ccc; border-radius: 3px; display: block; background: #f0f0f0; position: relative; }
            .tmnl-tpl-icon-card::after    { content: ""; display: block; position: absolute; top: 4px; left: 4px; right: 4px; bottom: 4px; background: repeating-linear-gradient(90deg, #ccc 0 10px, transparent 10px 14px); }
            .tmnl-tpl-icon-slider::after  { content: "❮ ❯"; position: absolute; inset: 0; display: flex; align-items: center; justify-content: space-between; padding: 0 3px; font-size: 10px; color: #999; }
            .tmnl-tpl-icon-list::after    { content: ""; display: block; position: absolute; top: 5px; left: 5px; right: 5px; bottom: 5px; background: repeating-linear-gradient(180deg, #ccc 0 2px, transparent 2px 7px); }
            .tmnl-tpl-icon-badge::after   { content: "★4.9"; position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 9px; color: #f5a623; font-weight: 700; }
            .tmnl-tpl-icon-floating::after{ content: "💬"; position: absolute; inset: 0; display: flex; align-items: center; justify-content: center; font-size: 16px; }

            /* Shortcode copy */
            .tmnl-shortcode-copy-box { display: inline-flex; align-items: center; gap: 12px; background: #f0f6fc; border: 1px solid #2271b1; border-radius: 4px; padding: 10px 16px; }
            .tmnl-shortcode-copy-box code { font-size: 14px; }
            .tmnl-cache-info { background: #f0f6fc; border-left: 4px solid #2271b1; padding: 10px 14px; margin-bottom: 14px; font-size: 13px; }

            /* Upgrade banner */
            .tmnl-upgrade-banner { background: linear-gradient(135deg, #1d2327 0%, #2271b1 100%); border-radius: 6px; padding: 20px 24px; margin-top: 4px; }
            .tmnl-upgrade-banner-inner { display: flex; align-items: center; justify-content: space-between; gap: 16px; flex-wrap: wrap; }
            .tmnl-upgrade-banner-text { display: flex; flex-direction: column; gap: 4px; color: #fff; }
            .tmnl-upgrade-banner-text strong { font-size: 16px; }
            .tmnl-upgrade-banner-text span { font-size: 13px; opacity: 0.85; }
            .tmnl-upgrade-banner-actions { display: flex; flex-direction: column; align-items: flex-end; gap: 6px; }
            .tmnl-upgrade-button { background: #f0b429 !important; border-color: #d99800 !important; color: #1d2327 !important; font-weight: 700 !important; padding: 8px 20px !important; height: auto !important; cursor: pointer; }
            .tmnl-upgrade-button:hover { background: #ffd166 !important; }
            .tmnl-upgrade-learnmore { color: rgba(255,255,255,0.7); font-size: 12px; text-align: center; text-decoration: underline; }
            .tmnl-upgrade-learnmore:hover { color: #fff; }
            .tmnl-compare-table-wrap { margin-top: 16px; }
            .tmnl-compare-table { width: 100%; max-width: 560px; border-collapse: collapse; font-size: 13px; }
            .tmnl-compare-table th { color: #fff; text-align: left; padding: 6px 10px; font-weight: 600; border-bottom: 1px solid rgba(255,255,255,0.2); }
            .tmnl-compare-table th:not(:first-child) { text-align: center; width: 80px; }
            .tmnl-compare-table td { padding: 5px 10px; color: rgba(255,255,255,0.85); border-bottom: 1px solid rgba(255,255,255,0.08); }
            .tmnl-compare-table td:not(:first-child) { text-align: center; font-size: 15px; }
            .tmnl-compare-table .tmnl-yes { color: #7ee787; font-weight: 700; }
            .tmnl-compare-table .tmnl-no  { color: rgba(255,255,255,0.3); }
            .tmnl-compare-table .tmnl-pro-row td:first-child { font-weight: 600; color: #ffd166; }

            /* Wizard */
            .tmnl-wizard-steps { display: flex; align-items: center; margin: 24px 0; }
            .tmnl-wizard-step-item { display: flex; align-items: center; gap: 8px; font-size: 13px; color: #999; }
            .tmnl-step-num { width: 28px; height: 28px; border-radius: 50%; background: #e0e0e0; color: #666; display: flex; align-items: center; justify-content: center; font-weight: 700; font-size: 13px; }
            .tmnl-step-active .tmnl-step-num { background: #2271b1; color: #fff; }
            .tmnl-step-active .tmnl-step-label { color: #1d2327; font-weight: 600; }
            .tmnl-step-done .tmnl-step-num { background: #2e7d32; color: #fff; }
            .tmnl-wizard-step-sep { flex: 1; height: 2px; background: #e0e0e0; margin: 0 12px; max-width: 80px; }
            .tmnl-wizard-panel { background: #fff; border: 1px solid #ccd0d4; border-radius: 6px; padding: 24px 28px; margin-bottom: 20px; }
            .tmnl-wizard-nav { margin-top: 20px; }
            .tmnl-wizard-design-row { display: flex; gap: 24px; align-items: flex-start; flex-wrap: wrap; }
            .tmnl-wizard-design-controls { flex: 0 0 420px; }
            .tmnl-wizard-design-controls .form-table th { width: 100px; }
            .tmnl-wizard-preview-pane { flex: 1; min-width: 260px; }
            .tmnl-wizard-done { text-align: center; padding: 16px; }
            .tmnl-done-icon { font-size: 64px; width: 64px; height: 64px; color: #2e7d32; display: block; margin: 0 auto 16px; }
        ';
    }
}
