<?php
// phpcs:disable WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQL.NotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber
// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.DirectDatabaseQuery.SchemaChange
/**
 * Yatoon Growth Storefront - customer-facing self-service purchase page for
 * packages and memberships. Renders the [yatoon_growth_storefront] shortcode
 * and exposes two AJAX endpoints:
 *
 *   yatoon_growth_create_purchase  - server-side validation + price calc;
 *                                    creates a pending row and (if Stripe is
 *                                    configured) a PaymentIntent.
 *   yatoon_growth_confirm_purchase - called by the browser after Stripe.js
 *                                    confirms the card; verifies the intent
 *                                    server-side and activates the row.
 *
 * If Stripe is NOT configured, the storefront falls back to "request mode":
 * the row is saved as status='pending' and an admin notification is sent so
 * the salon can collect payment in person and grant the package/membership
 * from the Growth Modules admin page.
 *
 * Activated rows are also activated by the Stripe webhook (via
 * activate_purchase_by_intent) for redundancy if the browser drops the
 * confirm AJAX request.
 */

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

class YATOON_Growth_Storefront {

    public static function init() {
        add_action( 'init', array( __CLASS__, 'maybe_create_columns' ), 6 );
        add_shortcode( 'yatoon_growth_storefront', array( __CLASS__, 'render_shortcode' ) );
        add_action( 'wp_ajax_yatoon_growth_create_purchase',  array( __CLASS__, 'ajax_create_purchase' ) );
        add_action( 'wp_ajax_nopriv_yatoon_growth_create_purchase',  array( __CLASS__, 'ajax_create_purchase' ) );
        add_action( 'wp_ajax_yatoon_growth_confirm_purchase', array( __CLASS__, 'ajax_confirm_purchase' ) );
        add_action( 'wp_ajax_nopriv_yatoon_growth_confirm_purchase', array( __CLASS__, 'ajax_confirm_purchase' ) );
    }

    /**
     * Add columns we need for purchase tracking. Idempotent - safe to run on
     * every request. We avoid dbDelta here because it cannot rename existing
     * columns and we only need to add new ones.
     */
    public static function maybe_create_columns() {
        global $wpdb;
        $installed_schema_version = (string) get_option( 'yatoon_growth_storefront_schema_version', '0' );
        if ( !yatoon_should_run_schema_migration( $installed_schema_version, YATOON_DB_VERSION ) ) {
            return;
        }

        $tables = array( 'yatoon_customer_packages', 'yatoon_customer_memberships' );
        foreach ( $tables as $tbl ) {
            $full = $wpdb->prefix . sanitize_key( $tbl );
            $safe_full = esc_sql( $full );
            $exists = $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $full ) );
            if ( ! $exists ) continue;
            $cols = $wpdb->get_col( "SHOW COLUMNS FROM `{$safe_full}`", 0 ); // phpcs:ignore
            if ( ! in_array( 'stripe_intent_id', (array) $cols, true ) ) {
                $wpdb->query( "ALTER TABLE `{$safe_full}` ADD COLUMN stripe_intent_id varchar(100) DEFAULT NULL AFTER status" );
                $wpdb->query( "ALTER TABLE `{$safe_full}` ADD INDEX stripe_intent_id (stripe_intent_id)" );
            }
            if ( ! in_array( 'source', (array) $cols, true ) ) {
                $wpdb->query( "ALTER TABLE `{$safe_full}` ADD COLUMN source varchar(30) DEFAULT 'admin' AFTER stripe_intent_id" );
            }
        }
        update_option( 'yatoon_growth_storefront_schema_version', YATOON_DB_VERSION );
    }

    /* ---------------------------------------------------------------------
       Shortcode
       --------------------------------------------------------------------- */

    public static function render_shortcode( $atts = array() ) {
        if ( ! class_exists( 'YATOON_License' ) || ! YATOON_License::is_pro() ) {
            return '<div class="yatoon-storefront-empty"><p>' . esc_html__( 'Package and membership storefronts require an active Yatoon Pro license.', 'yatoon-booking-system' ) . '</p></div>';
        }

        $atts = shortcode_atts( array(
            'show'    => 'both', // both | packages | memberships
            'title'   => __( 'Buy a Package or Membership', 'yatoon-booking-system' ),
        ), $atts, 'yatoon_growth_storefront' );

        global $wpdb;
        $packages    = ( $atts['show'] !== 'memberships' && YATOON_Growth_Modules::is_enabled( 'packages' ) )
            ? $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}yatoon_packages WHERE is_active = 1 ORDER BY price ASC, id ASC" )
            : array();
        $memberships = ( $atts['show'] !== 'packages' && YATOON_Growth_Modules::is_enabled( 'memberships' ) )
            ? $wpdb->get_results( "SELECT * FROM {$wpdb->prefix}yatoon_memberships WHERE is_active = 1 ORDER BY price ASC, id ASC" )
            : array();

        if ( empty( $packages ) && empty( $memberships ) ) {
            return '<div class="yatoon-storefront-empty"><p>' . esc_html__( 'No packages or memberships are available right now. Please check back later.', 'yatoon-booking-system' ) . '</p></div>';
        }

        $stripe_ready = class_exists( 'Yatoon_Stripe' ) && Yatoon_Stripe::is_configured();
        // Existing settings UI stores the publishable key as
        // yatoon_deposit_stripe_key (see admin/views/settings.php).
        $publishable  = trim( get_option( 'yatoon_deposit_stripe_key', '' ) );
        if ( $stripe_ready && empty( $publishable ) ) {
            // Stripe secret is set but publishable key is missing - fall back
            // to request mode rather than rendering a broken card form.
            $stripe_ready = false;
        }

        ob_start();
        // Inline assets - keep the storefront self-contained so it works on
        // any page without depending on the booking form being loaded too.
        if ( $stripe_ready ) {
            wp_enqueue_script( 'yatoon-stripe-js', 'https://js.stripe.com/v3/', array(), '3', true );
        }

        $nonce = wp_create_nonce( 'yatoon_storefront_nonce' );
        ?>
        <div class="yatoon-storefront" data-stripe="<?php echo esc_attr( $stripe_ready ? '1' : '0' ); ?>" data-pk="<?php echo esc_attr( $publishable ); ?>" data-nonce="<?php echo esc_attr( $nonce ); ?>" data-ajax="<?php echo esc_url( admin_url( 'admin-ajax.php' ) ); ?>">
            <h2 class="yatoon-storefront-title"><?php echo esc_html( $atts['title'] ); ?></h2>
            <?php if ( ! empty( $packages ) ) : ?>
                <h3><?php esc_html_e( 'Packages', 'yatoon-booking-system' ); ?></h3>
                <div class="yatoon-storefront-grid">
                    <?php foreach ( $packages as $p ) : ?>
                        <div class="yatoon-storefront-card" data-type="package" data-id="<?php echo esc_attr( intval( $p->id ) ); ?>">
                            <h4><?php echo esc_html( $p->name ); ?></h4>
                            <?php if ( $p->description ) : ?><p class="ys-desc"><?php echo esc_html( $p->description ); ?></p><?php endif; ?>
                            <p class="ys-meta">
                                <strong><?php echo esc_html( number_format( floatval( $p->price ), 2 ) ); ?></strong>
                                &mdash; <?php
                                /* translators: %d: number of included package visits. */
                                echo esc_html( sprintf( _n( '%d visit', '%d visits', intval( $p->included_visits ), 'yatoon-booking-system' ), intval( $p->included_visits ) ) );
                                ?>,
                                <?php
                                /* translators: %d: number of days the package remains valid. */
                                echo esc_html( sprintf( _n( 'valid %d day', 'valid %d days', intval( $p->validity_days ), 'yatoon-booking-system' ), intval( $p->validity_days ) ) );
                                ?>
                            </p>
                            <button type="button" class="ys-buy-btn"><?php esc_html_e( 'Buy Now', 'yatoon-booking-system' ); ?></button>
                        </div>
                    <?php endforeach; ?>
                </div>
            <?php endif; ?>

            <?php if ( ! empty( $memberships ) ) : ?>
                <h3><?php esc_html_e( 'Memberships', 'yatoon-booking-system' ); ?></h3>
                <div class="yatoon-storefront-grid">
                    <?php foreach ( $memberships as $m ) : ?>
                        <div class="yatoon-storefront-card" data-type="membership" data-id="<?php echo esc_attr( intval( $m->id ) ); ?>">
                            <h4><?php echo esc_html( $m->name ); ?></h4>
                            <?php if ( $m->description ) : ?><p class="ys-desc"><?php echo esc_html( $m->description ); ?></p><?php endif; ?>
                            <p class="ys-meta">
                                <strong>$<?php echo esc_html( number_format( floatval( $m->price ), 2 ) ); ?></strong>
                                / <?php echo esc_html( $m->billing_period === 'yearly' ? __( 'year', 'yatoon-booking-system' ) : __( 'month', 'yatoon-booking-system' ) ); ?>
                                <?php if ( floatval( $m->booking_discount_percent ) > 0 ) : ?>
                                    &mdash; <?php
                                    /* translators: %s: membership booking discount percentage. */
                                    echo esc_html( sprintf( __( '%s%% off every booking', 'yatoon-booking-system' ), rtrim( rtrim( number_format( floatval( $m->booking_discount_percent ), 2 ), '0' ), '.' ) ) );
                                    ?>
                                <?php endif; ?>
                            </p>
                            <button type="button" class="ys-buy-btn"><?php esc_html_e( 'Join Now', 'yatoon-booking-system' ); ?></button>
                        </div>
                    <?php endforeach; ?>
                </div>
            <?php endif; ?>

            <div class="yatoon-storefront-modal" hidden>
                <div class="ys-modal-inner">
                    <button type="button" class="ys-modal-close" aria-label="Close">&times;</button>
                    <h3 class="ys-modal-title"></h3>
                    <p class="ys-modal-summary"></p>
                    <form class="ys-purchase-form">
                        <p><label><?php esc_html_e( 'Full name', 'yatoon-booking-system' ); ?> *<br><input type="text" name="customer_name" required></label></p>
                        <p><label><?php esc_html_e( 'Email', 'yatoon-booking-system' ); ?> *<br><input type="email" name="customer_email" required></label></p>
                        <p><label><?php esc_html_e( 'Phone', 'yatoon-booking-system' ); ?> *<br><input type="tel" name="customer_phone" required></label></p>
                        <?php if ( $stripe_ready ) : ?>
                            <div class="ys-card-wrap">
                                <label><?php esc_html_e( 'Card details', 'yatoon-booking-system' ); ?> *</label>
                                <div class="ys-card-element"></div>
                                <div class="ys-card-error" role="alert"></div>
                            </div>
                        <?php else : ?>
                            <p class="ys-notice"><?php esc_html_e( 'Online payment is not configured yet. Submit your request and we will contact you to confirm and arrange payment in person.', 'yatoon-booking-system' ); ?></p>
                        <?php endif; ?>
                        <p class="ys-status" aria-live="polite"></p>
                        <p><button type="submit" class="ys-submit"><?php echo esc_html( $stripe_ready ? __( 'Pay & Activate', 'yatoon-booking-system' ) : __( 'Submit Request', 'yatoon-booking-system' ) ); ?></button></p>
                    </form>
                </div>
            </div>
        </div>

        <style>
            .yatoon-storefront{max-width:980px;margin:24px auto;font-family:inherit}
            .yatoon-storefront-title{margin:0 0 12px;font-size:1.6em}
            .yatoon-storefront-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(250px,1fr));gap:16px;margin:12px 0 28px}
            .yatoon-storefront-card{border:1px solid #e2e2e6;border-radius:10px;padding:18px;background:#fff;display:flex;flex-direction:column;justify-content:space-between}
            .yatoon-storefront-card h4{margin:0 0 6px;font-size:1.15em}
            .yatoon-storefront-card .ys-desc{margin:0 0 10px;color:#555;font-size:0.95em}
            .yatoon-storefront-card .ys-meta{margin:0 0 12px;color:#222}
            .yatoon-storefront-card .ys-meta strong{font-size:1.15em}
            .ys-buy-btn{background:#111;color:#fff;border:0;border-radius:8px;padding:10px 16px;font-weight:600;cursor:pointer}
            .ys-buy-btn:hover{background:#000}
            .yatoon-storefront-modal{position:fixed;inset:0;background:rgba(0,0,0,0.55);display:flex;align-items:center;justify-content:center;z-index:99999;padding:16px}
            .yatoon-storefront-modal[hidden]{display:none}
            .ys-modal-inner{background:#fff;border-radius:12px;padding:24px;max-width:460px;width:100%;position:relative;box-shadow:0 10px 30px rgba(0,0,0,0.2)}
            .ys-modal-close{position:absolute;top:8px;right:12px;background:none;border:0;font-size:1.6em;line-height:1;cursor:pointer;color:#666}
            .ys-modal-title{margin:0 0 6px}
            .ys-modal-summary{margin:0 0 16px;color:#444}
            .ys-purchase-form input[type=text],.ys-purchase-form input[type=email],.ys-purchase-form input[type=tel]{width:100%;padding:8px 10px;border:1px solid #ccd0d4;border-radius:6px}
            .ys-card-wrap{margin:12px 0}
            .ys-card-element{padding:10px;border:1px solid #ccd0d4;border-radius:6px;background:#fff}
            .ys-card-error{color:#b32d2e;font-size:0.9em;min-height:1.2em;margin-top:4px}
            .ys-status{min-height:1.2em;margin:8px 0;color:#444}
            .ys-status.ys-success{color:#0a7d3b;font-weight:600}
            .ys-status.ys-error{color:#b32d2e;font-weight:600}
            .ys-submit{background:#0a7d3b;color:#fff;border:0;border-radius:8px;padding:10px 18px;font-weight:600;cursor:pointer;width:100%}
            .ys-submit:disabled{opacity:0.6;cursor:not-allowed}
            .ys-notice{background:#fffbe6;border:1px solid #f0c36d;padding:10px;border-radius:6px;font-size:0.95em}
        </style>

        <script>
        (function(){
            var root = document.currentScript && document.currentScript.previousElementSibling;
            // Fallback: locate the storefront DOM by class.
            var nodes = document.querySelectorAll('.yatoon-storefront');
            nodes.forEach(function(node){
                if ( node.dataset.bound === '1' ) return;
                node.dataset.bound = '1';
                var stripeReady = node.dataset.stripe === '1';
                var pk          = node.dataset.pk;
                var ajaxUrl     = node.dataset.ajax;
                var nonce       = node.dataset.nonce;

                var modal = node.querySelector('.yatoon-storefront-modal');
                var form  = node.querySelector('.ys-purchase-form');
                var status = node.querySelector('.ys-status');
                var titleEl = node.querySelector('.ys-modal-title');
                var sumEl   = node.querySelector('.ys-modal-summary');
                var submit  = node.querySelector('.ys-submit');
                var errEl   = node.querySelector('.ys-card-error');
                var current = { type:'', id:0, label:'' };

                var stripe = null, elements = null, card = null;
                if ( stripeReady && pk && window.Stripe ) {
                    try {
                        stripe   = window.Stripe(pk);
                        elements = stripe.elements();
                        card     = elements.create('card');
                        card.mount(node.querySelector('.ys-card-element'));
                        card.on('change', function(e){ errEl.textContent = e.error ? e.error.message : ''; });
                    } catch(e){ console.error('Stripe init failed', e); stripeReady = false; }
                }

                function openModal(card){
                    current.type  = card.dataset.type;
                    current.id    = parseInt(card.dataset.id, 10);
                    current.label = card.querySelector('h4').textContent.trim();
                    titleEl.textContent = current.label;
                    sumEl.textContent   = card.querySelector('.ys-meta').textContent.trim();
                    status.textContent  = '';
                    status.className    = 'ys-status';
                    modal.hidden = false;
                }
                function closeModal(){ modal.hidden = true; }

                node.querySelectorAll('.ys-buy-btn').forEach(function(btn){
                    btn.addEventListener('click', function(){ openModal(btn.closest('.yatoon-storefront-card')); });
                });
                node.querySelector('.ys-modal-close').addEventListener('click', closeModal);
                modal.addEventListener('click', function(e){ if(e.target===modal) closeModal(); });

                form.addEventListener('submit', function(ev){
                    ev.preventDefault();
                    submit.disabled = true;
                    status.className = 'ys-status';
                    status.textContent = '...';

                    var fd = new FormData();
                    fd.append('action', 'yatoon_growth_create_purchase');
                    fd.append('nonce', nonce);
                    fd.append('item_type', current.type);
                    fd.append('item_id', current.id);
                    fd.append('customer_name',  form.customer_name.value);
                    fd.append('customer_email', form.customer_email.value);
                    fd.append('customer_phone', form.customer_phone.value);

                    fetch(ajaxUrl, { method:'POST', body: fd, credentials:'same-origin' })
                        .then(function(r){ return r.json(); })
                        .then(function(json){
                            if (!json || !json.success) {
                                status.className = 'ys-status ys-error';
                                status.textContent = (json && json.data && json.data.message) ? json.data.message : 'Could not start purchase.';
                                submit.disabled = false;
                                return;
                            }
                            var purchaseId = json.data.purchase_id;
                            if ( stripeReady && json.data.client_secret && stripe && card ) {
                                status.textContent = 'Confirming payment...';
                                stripe.confirmCardPayment(json.data.client_secret, {
                                    payment_method: { card: card, billing_details: { name: form.customer_name.value, email: form.customer_email.value } }
                                }).then(function(result){
                                    if (result.error) {
                                        status.className = 'ys-status ys-error';
                                        status.textContent = result.error.message || 'Payment failed.';
                                        submit.disabled = false;
                                        return;
                                    }
                                    var fd2 = new FormData();
                                    fd2.append('action','yatoon_growth_confirm_purchase');
                                    fd2.append('nonce', nonce);
                                    fd2.append('purchase_id', purchaseId);
                                    fd2.append('intent_id', result.paymentIntent.id);
                                    fetch(ajaxUrl, { method:'POST', body:fd2, credentials:'same-origin' })
                                        .then(function(r){ return r.json(); })
                                        .then(function(json2){
                                            if (json2 && json2.success) {
                                                status.className = 'ys-status ys-success';
                                                status.textContent = json2.data.message || 'Activated!';
                                                form.reset();
                                            } else {
                                                status.className = 'ys-status ys-error';
                                                status.textContent = (json2 && json2.data && json2.data.message) ? json2.data.message : 'Activation failed. Please contact us.';
                                            }
                                            submit.disabled = false;
                                        });
                                });
                            } else {
                                status.className = 'ys-status ys-success';
                                status.textContent = json.data.message || 'Request received. We will contact you shortly.';
                                form.reset();
                                submit.disabled = false;
                            }
                        })
                        .catch(function(){
                            status.className = 'ys-status ys-error';
                            status.textContent = 'Network error. Please try again.';
                            submit.disabled = false;
                        });
                });
            });
        })();
        </script>
        <?php
        return ob_get_clean();
    }

    /* ---------------------------------------------------------------------
       AJAX
       --------------------------------------------------------------------- */

    public static function ajax_create_purchase() {
        check_ajax_referer( 'yatoon_storefront_nonce', 'nonce' );

        if ( ! class_exists( 'YATOON_License' ) || ! YATOON_License::is_pro() ) {
            wp_send_json_error( array( 'message' => __( 'Storefront purchases require an active Yatoon Pro license.', 'yatoon-booking-system' ) ) );
        }

        $item_type = isset( $_POST['item_type'] ) ? sanitize_key( wp_unslash( $_POST['item_type'] ) ) : '';
        $item_id   = isset( $_POST['item_id'] )   ? absint( $_POST['item_id'] )                       : 0;
        $name      = isset( $_POST['customer_name'] )  ? sanitize_text_field( wp_unslash( $_POST['customer_name'] ) )  : '';
        $email     = isset( $_POST['customer_email'] ) ? sanitize_email( wp_unslash( $_POST['customer_email'] ) )      : '';
        $phone     = isset( $_POST['customer_phone'] ) ? sanitize_text_field( wp_unslash( $_POST['customer_phone'] ) ) : '';

        if ( ! in_array( $item_type, array( 'package', 'membership' ), true ) ) {
            wp_send_json_error( array( 'message' => __( 'Invalid item.', 'yatoon-booking-system' ) ) );
        }
        if ( ! $item_id || $name === '' || ! is_email( $email ) || $phone === '' ) {
            wp_send_json_error( array( 'message' => __( 'Please fill in your name, a valid email and phone number.', 'yatoon-booking-system' ) ) );
        }

        // Light rate-limit: max 5 requests per IP per 10 min.
        $ip = isset( $_SERVER['REMOTE_ADDR'] ) ? sanitize_text_field( wp_unslash( $_SERVER['REMOTE_ADDR'] ) ) : '';
        if ( $ip ) {
            $rk    = 'yatoon_sf_rate_' . md5( $ip );
            $count = (int) get_transient( $rk );
            if ( $count >= 5 ) {
                wp_send_json_error( array( 'message' => __( 'Too many attempts. Please wait a few minutes.', 'yatoon-booking-system' ) ) );
            }
            set_transient( $rk, $count + 1, 10 * MINUTE_IN_SECONDS );
        }

        global $wpdb;
        $module_enabled = ( $item_type === 'package' )
            ? YATOON_Growth_Modules::is_enabled( 'packages' )
            : YATOON_Growth_Modules::is_enabled( 'memberships' );
        if ( ! $module_enabled ) {
            wp_send_json_error( array( 'message' => __( 'This module is not currently available.', 'yatoon-booking-system' ) ) );
        }

        if ( $item_type === 'package' ) {
            $row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}yatoon_packages WHERE id = %d AND is_active = 1", $item_id ) );
            if ( ! $row ) wp_send_json_error( array( 'message' => __( 'Package is no longer available.', 'yatoon-booking-system' ) ) );
            $price_cents = (int) round( floatval( $row->price ) * 100 );
            $description = sprintf( 'Package: %s', $row->name );
        } else {
            $row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$wpdb->prefix}yatoon_memberships WHERE id = %d AND is_active = 1", $item_id ) );
            if ( ! $row ) wp_send_json_error( array( 'message' => __( 'Membership is no longer available.', 'yatoon-booking-system' ) ) );
            $price_cents = (int) round( floatval( $row->price ) * 100 );
            $description = sprintf( 'Membership: %s', $row->name );
        }
        if ( $price_cents <= 0 ) {
            wp_send_json_error( array( 'message' => __( 'This item has no price set. Please contact us.', 'yatoon-booking-system' ) ) );
        }

        // Insert pending row first so we have a stable id for Stripe metadata.
        $purchase_id = self::insert_pending_row( $item_type, $row, $name, $email, $phone );
        if ( ! $purchase_id ) {
            wp_send_json_error( array( 'message' => __( 'Could not create purchase record. Please try again.', 'yatoon-booking-system' ) ) );
        }

        if ( class_exists( 'Yatoon_Stripe' ) && Yatoon_Stripe::is_configured() ) {
            $intent = Yatoon_Stripe::create_purchase_intent(
                $price_cents,
                $email,
                $description,
                array(
                    'yatoon_source' => 'growth_storefront',
                    'item_type'     => $item_type,
                    'item_id'       => $item_id,
                    'purchase_id'   => $purchase_id,
                )
            );
            if ( is_wp_error( $intent ) || empty( $intent['client_secret'] ) ) {
                self::delete_pending_row( $item_type, $purchase_id );
                wp_send_json_error( array( 'message' => is_wp_error( $intent ) ? $intent->get_error_message() : __( 'Payment provider error.', 'yatoon-booking-system' ) ) );
            }
            $table = ( $item_type === 'package' )
                ? $wpdb->prefix . 'yatoon_customer_packages'
                : $wpdb->prefix . 'yatoon_customer_memberships';
            $wpdb->update( $table, array( 'stripe_intent_id' => $intent['id'] ), array( 'id' => $purchase_id ), array( '%s' ), array( '%d' ) );
            wp_send_json_success( array(
                'purchase_id'   => $purchase_id,
                'client_secret' => $intent['client_secret'],
                'intent_id'     => $intent['id'],
                'mode'          => 'stripe',
            ) );
        }

        // Manual / request mode
        self::notify_admin_manual_request( $item_type, $row, $purchase_id, $name, $email, $phone );
        wp_send_json_success( array(
            'purchase_id' => $purchase_id,
            'mode'        => 'manual',
            'message'     => __( 'Request received. We will contact you shortly to confirm and arrange payment.', 'yatoon-booking-system' ),
        ) );
    }

    public static function ajax_confirm_purchase() {
        check_ajax_referer( 'yatoon_storefront_nonce', 'nonce' );

        if ( ! class_exists( 'YATOON_License' ) || ! YATOON_License::is_pro() ) {
            wp_send_json_error( array( 'message' => __( 'Storefront purchases require an active Yatoon Pro license.', 'yatoon-booking-system' ) ) );
        }

        $intent_id   = isset( $_POST['intent_id'] )   ? sanitize_text_field( wp_unslash( $_POST['intent_id'] ) ) : '';
        $purchase_id = isset( $_POST['purchase_id'] ) ? absint( $_POST['purchase_id'] )                          : 0;
        if ( ! $intent_id || ! $purchase_id ) {
            wp_send_json_error( array( 'message' => __( 'Missing data.', 'yatoon-booking-system' ) ) );
        }

        $verify = class_exists( 'Yatoon_Stripe' ) ? Yatoon_Stripe::verify_payment( $intent_id ) : new WP_Error( 'no_stripe', 'Stripe unavailable.' );
        if ( is_wp_error( $verify ) ) {
            wp_send_json_error( array( 'message' => $verify->get_error_message() ) );
        }

        $activated = self::activate_purchase_by_intent( $intent_id );
        if ( ! $activated ) {
            wp_send_json_error( array( 'message' => __( 'Payment confirmed but activation failed. Please contact us.', 'yatoon-booking-system' ) ) );
        }
        wp_send_json_success( array( 'message' => __( 'Payment received. Your package/membership is now active!', 'yatoon-booking-system' ) ) );
    }

    /* ---------------------------------------------------------------------
       Helpers
       --------------------------------------------------------------------- */

    private static function insert_pending_row( $item_type, $row, $name, $email, $phone ) {
        global $wpdb;
        $today = current_time( 'Y-m-d' );

        if ( $item_type === 'package' ) {
            $expires = gmdate( 'Y-m-d', strtotime( $today . ' +' . max( 1, intval( $row->validity_days ) ) . ' days' ) );
            $ok = $wpdb->insert( $wpdb->prefix . 'yatoon_customer_packages', array(
                'package_id'       => intval( $row->id ),
                'customer_name'    => $name,
                'customer_email'   => $email,
                'customer_phone'   => $phone,
                'purchased_visits' => intval( $row->included_visits ),
                'remaining_visits' => intval( $row->included_visits ),
                'paid_amount'      => floatval( $row->price ),
                'starts_at'        => $today,
                'expires_at'       => $expires,
                'status'           => 'pending',
                'source'           => 'storefront',
                'notes'            => 'Purchased via storefront',
            ) );
        } else {
            $days    = ( $row->billing_period === 'yearly' ) ? 365 : 30;
            $expires = gmdate( 'Y-m-d', strtotime( $today . ' +' . $days . ' days' ) );
            $ok = $wpdb->insert( $wpdb->prefix . 'yatoon_customer_memberships', array(
                'membership_id'  => intval( $row->id ),
                'customer_name'  => $name,
                'customer_email' => $email,
                'customer_phone' => $phone,
                'paid_amount'    => floatval( $row->price ),
                'starts_at'      => $today,
                'expires_at'     => $expires,
                'status'         => 'pending',
                'source'         => 'storefront',
                'notes'          => 'Purchased via storefront',
            ) );
        }
        return $ok ? intval( $wpdb->insert_id ) : 0;
    }

    private static function delete_pending_row( $item_type, $purchase_id ) {
        global $wpdb;
        $tbl = ( $item_type === 'package' )
            ? $wpdb->prefix . 'yatoon_customer_packages'
            : $wpdb->prefix . 'yatoon_customer_memberships';
        $wpdb->delete( $tbl, array( 'id' => intval( $purchase_id ), 'status' => 'pending' ), array( '%d', '%s' ) );
    }

    /**
     * Activate a pending purchase row matched by Stripe intent id. Called both
     * by the customer-facing confirm AJAX and by the Stripe webhook so the
     * customer is provisioned even if the browser drops the AJAX after pay.
     *
     * Idempotent - calling twice on an already-active row is a no-op.
     */
    public static function activate_purchase_by_intent( $intent_id ) {
        if ( empty( $intent_id ) ) return false;
        global $wpdb;
        $tables = array(
            'package'    => $wpdb->prefix . 'yatoon_customer_packages',
            'membership' => $wpdb->prefix . 'yatoon_customer_memberships',
        );
        foreach ( $tables as $type => $tbl ) {
            $row = $wpdb->get_row( $wpdb->prepare( "SELECT * FROM {$tbl} WHERE stripe_intent_id = %s LIMIT 1", $intent_id ) );
            if ( ! $row ) continue;
            if ( $row->status === 'active' ) return true; // already activated
            $wpdb->update( $tbl,
                array( 'status' => 'active', 'updated_at' => current_time( 'mysql' ) ),
                array( 'id' => intval( $row->id ) ),
                array( '%s', '%s' ),
                array( '%d' )
            );
            self::send_buyer_receipt( $type, $row );
            self::notify_admin_purchase( $type, $row );
            return true;
        }
        return false;
    }

    public static function mark_purchase_refunded_by_intent( $intent_id ) {
        if ( empty( $intent_id ) ) return;
        global $wpdb;
        foreach ( array( 'yatoon_customer_packages', 'yatoon_customer_memberships' ) as $tbl ) {
            $wpdb->update(
                $wpdb->prefix . $tbl,
                array( 'status' => 'refunded', 'updated_at' => current_time( 'mysql' ) ),
                array( 'stripe_intent_id' => $intent_id ),
                array( '%s', '%s' ),
                array( '%s' )
            );
        }
    }

    private static function send_buyer_receipt( $type, $row ) {
        if ( empty( $row->customer_email ) || ! is_email( $row->customer_email ) ) return;
        $business = get_option( 'yatoon_business_name', get_bloginfo( 'name' ) );
        /* translators: %s: business name. */
        $subject  = sprintf( __( '[%s] Purchase confirmation', 'yatoon-booking-system' ), $business );
        $label    = ( $type === 'package' ) ? __( 'package', 'yatoon-booking-system' ) : __( 'membership', 'yatoon-booking-system' );
        $body     = sprintf(
            /* translators: 1: customer name, 2: purchase type, 3: expiration date, 4: business name. */
            __( "Hi %1\$s,\n\nThank you for your %2\$s purchase. It is now active and will be applied to your bookings automatically when you book using this email or phone number.\n\nValid until: %3\$s\n\n- %4\$s", 'yatoon-booking-system' ),
            $row->customer_name ?: __( 'there', 'yatoon-booking-system' ),
            $label,
            $row->expires_at ?: __( 'open-ended', 'yatoon-booking-system' ),
            $business
        );
        wp_mail( $row->customer_email, $subject, $body );
    }

    private static function notify_admin_purchase( $type, $row ) {
        $admin_email = get_option( 'yatoon_notify_email' ) ?: get_option( 'admin_email' );
        if ( ! $admin_email || ! is_email( $admin_email ) ) return;
        /* translators: 1: purchase type, 2: customer name. */
        $subject = sprintf( __( '[Yatoon] New %1$s purchase: %2$s', 'yatoon-booking-system' ), $type, $row->customer_name );
        $body    = sprintf(
            "%s purchase activated.\n\nName : %s\nEmail: %s\nPhone: %s\nPaid : $%s\nValid: %s -> %s",
            ucfirst( $type ),
            $row->customer_name,
            $row->customer_email,
            $row->customer_phone,
            number_format( floatval( $row->paid_amount ), 2 ),
            $row->starts_at,
            $row->expires_at
        );
        wp_mail( $admin_email, $subject, $body );
    }

    private static function notify_admin_manual_request( $type, $item, $purchase_id, $name, $email, $phone ) {
        $admin_email = get_option( 'yatoon_notify_email' ) ?: get_option( 'admin_email' );
        if ( ! $admin_email || ! is_email( $admin_email ) ) return;
        /* translators: 1: purchase type, 2: customer name. */
        $subject = sprintf( __( '[Yatoon] %1$s purchase request from %2$s', 'yatoon-booking-system' ), ucfirst( $type ), $name );
        $url     = admin_url( 'admin.php?page=yatoon-growth-modules' );
        $body    = sprintf(
            "A customer requested to buy a %s online but Stripe is not configured.\nPlease contact them, collect payment, then activate the row in Growth Modules.\n\nItem : %s ($%s)\nName : %s\nEmail: %s\nPhone: %s\nID   : %d\n\nReview: %s",
            $type,
            $item->name,
            number_format( floatval( $item->price ), 2 ),
            $name,
            $email,
            $phone,
            $purchase_id,
            $url
        );
        wp_mail( $admin_email, $subject, $body );
    }
}

YATOON_Growth_Storefront::init();
