<?php
/**
 * VMO Abandoned Cart Detection & Recovery System
 * 
 * Detects abandoned Stripe checkout sessions (orders stuck at 'created' status)
 * and sends automated recovery emails on the timing schedule:
 * - 1st reminder: +1 hour after abandonment
 * - 2nd reminder: +1 day after abandonment  
 * - 3rd reminder: +3 days after abandonment
 *
 * @package VMO_AI_Website_Builder
 * @since 1.0.52
 */

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

class VMO_Abandoned_Cart {

    private static $instance = null;
    private $table_name;
    private $orders_table;

    /** Recovery email timing schedule (matches enhanced-business-wizard config) */
    private $reminder_schedule = [
        1 => 3600,      // 1 hour
        2 => 86400,     // 1 day
        3 => 259200,    // 3 days
    ];

    public static function instance() {
        if (self::$instance === null) {
            self::$instance = new self();
        }
        return self::$instance;
    }

    public function __construct() {
        global $wpdb;
        $this->table_name   = $wpdb->prefix . 'vmo_abandoned_carts';
        $this->orders_table = $wpdb->prefix . 'vmo_store_orders';

        // Cron hooks
        add_action('vmo_check_abandoned_carts', [$this, 'detect_abandoned_carts']);
        add_action('vmo_send_recovery_emails',  [$this, 'send_recovery_emails']);

        // Schedule cron if not already scheduled
        if (!wp_next_scheduled('vmo_check_abandoned_carts')) {
            wp_schedule_event(time(), 'hourly', 'vmo_check_abandoned_carts');
        }
        if (!wp_next_scheduled('vmo_send_recovery_emails')) {
            wp_schedule_event(time(), 'hourly', 'vmo_send_recovery_emails');
        }

        // When a checkout completes, mark any matching abandoned cart as recovered
        add_action('vmo_checkout_completed', [$this, 'mark_recovered'], 10, 2);
    }

    /**
     * Create the abandoned carts table
     */
    public static function create_table() {
        global $wpdb;
        $table = $wpdb->prefix . 'vmo_abandoned_carts';
        $charset = $wpdb->get_charset_collate();

        $sql = "CREATE TABLE IF NOT EXISTS {$table} (
            id BIGINT UNSIGNED AUTO_INCREMENT PRIMARY KEY,
            order_id BIGINT UNSIGNED DEFAULT NULL,
            session_id VARCHAR(255) DEFAULT NULL,
            user_id BIGINT UNSIGNED DEFAULT NULL,
            customer_email VARCHAR(255) DEFAULT NULL,
            customer_name VARCHAR(255) DEFAULT NULL,
            product_id BIGINT UNSIGNED DEFAULT NULL,
            product_name VARCHAR(255) DEFAULT NULL,
            product_price DECIMAL(10,2) DEFAULT 0.00,
            currency VARCHAR(10) DEFAULT 'usd',
            cart_data LONGTEXT DEFAULT NULL,
            status ENUM('abandoned','reminded','recovered','expired') DEFAULT 'abandoned',
            reminder_count TINYINT UNSIGNED DEFAULT 0,
            last_reminder_at DATETIME DEFAULT NULL,
            recovered_at DATETIME DEFAULT NULL,
            discount_code VARCHAR(50) DEFAULT NULL,
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            KEY idx_status (status),
            KEY idx_email (customer_email),
            KEY idx_order (order_id),
            KEY idx_created (created_at)
        ) {$charset};";

        require_once ABSPATH . 'wp-admin/includes/upgrade.php';
        dbDelta($sql);
    }

    /**
     * Detect abandoned checkout sessions
     * Checks for orders with status='created' that are older than 1 hour
     * and haven't been tracked yet
     */
    public function detect_abandoned_carts() {
        global $wpdb;

        // Find orders stuck at 'created' for over 1 hour that aren't already tracked
        $one_hour_ago = gmdate('Y-m-d H:i:s', time() - 3600);

        $abandoned_orders = $wpdb->get_results($wpdb->prepare(
            "SELECT o.* FROM {$this->orders_table} o
             LEFT JOIN {$this->table_name} ac ON ac.order_id = o.id
             WHERE o.status = 'created'
             AND o.created_at < %s
             AND ac.id IS NULL
             ORDER BY o.created_at DESC
             LIMIT 50",
            $one_hour_ago
        ));

        if (empty($abandoned_orders)) return;

        foreach ($abandoned_orders as $order) {
            // Try to get customer email from the Stripe session
            $customer_email = '';
            $customer_name  = '';

            if (!empty($order->stripe_session_id)) {
                $email_data = $this->get_stripe_session_customer($order->stripe_session_id, $order->user_id);
                $customer_email = $email_data['email'] ?? '';
                $customer_name  = $email_data['name'] ?? '';
            }

            // Also check order metadata
            if (empty($customer_email) && !empty($order->customer_email)) {
                $customer_email = $order->customer_email;
            }

            // Try user email as fallback
            if (empty($customer_email) && !empty($order->user_id)) {
                $user = get_userdata($order->user_id);
                if ($user) {
                    $customer_email = $user->user_email;
                    if (empty($customer_name)) {
                        $customer_name = $user->display_name;
                    }
                }
            }

            // Get product info
            $product_name  = $order->product_name ?? 'Unknown Product';
            $product_price = $order->amount ?? 0;
            $currency      = $order->currency ?? 'usd';

            $cart_data = json_encode([
                'order_id'    => $order->id,
                'product_id'  => $order->product_id ?? null,
                'product_name'=> $product_name,
                'amount'      => $product_price,
                'currency'    => $currency,
                'session_id'  => $order->stripe_session_id ?? null,
            ]);

            $wpdb->insert($this->table_name, [
                'order_id'       => $order->id,
                'session_id'     => $order->stripe_session_id ?? null,
                'user_id'        => $order->user_id ?? null,
                'customer_email' => $customer_email,
                'customer_name'  => $customer_name,
                'product_id'     => $order->product_id ?? null,
                'product_name'   => $product_name,
                'product_price'  => $product_price,
                'currency'       => strtolower($currency),
                'cart_data'      => $cart_data,
                'status'         => 'abandoned',
                'reminder_count' => 0,
                'created_at'     => $order->created_at,
            ]);
        }

        // Log detection count
        $count = count($abandoned_orders);
        if ($count > 0) {
            error_log("[VMO Abandoned Cart] Detected {$count} new abandoned checkout(s)");
        }
    }

    /**
     * Try to get customer details from Stripe session
     */
    private function get_stripe_session_customer($session_id, $user_id = null) {
        $result = ['email' => '', 'name' => ''];

        try {
            $stripe_secret = get_option('vmo_stripe_secret_key', '');
            if (empty($stripe_secret)) return $result;

            // Get connected account for this user
            if ($user_id) {
                global $wpdb;
                $connected_table = $wpdb->prefix . 'vmo_connected_accounts';
                $account_id = $wpdb->get_var($wpdb->prepare(
                    "SELECT stripe_account_id FROM {$connected_table} WHERE user_id = %d LIMIT 1",
                    $user_id
                ));
            }

            $params = [];
            if (!empty($account_id)) {
                $params['stripe_account'] = $account_id;
            }

            \Stripe\Stripe::setApiKey($stripe_secret);
            $session = \Stripe\Checkout\Session::retrieve($session_id, $params);

            if (!empty($session->customer_details)) {
                $result['email'] = $session->customer_details->email ?? '';
                $result['name']  = $session->customer_details->name ?? '';
            } elseif (!empty($session->customer_email)) {
                $result['email'] = $session->customer_email;
            }
        } catch (\Exception $e) {
            // Silently fail — email will be empty
        }

        return $result;
    }

    /**
     * Send scheduled recovery emails
     * Respects the timing schedule: +1hr, +1day, +3days
     */
    public function send_recovery_emails() {
        global $wpdb;

        // Get abandoned carts that need reminders
        $carts = $wpdb->get_results(
            "SELECT * FROM {$this->table_name}
             WHERE status IN ('abandoned', 'reminded')
             AND reminder_count < 3
             AND customer_email != ''
             AND customer_email IS NOT NULL
             ORDER BY created_at ASC
             LIMIT 20"
        );

        if (empty($carts)) return;

        $sent = 0;
        foreach ($carts as $cart) {
            $next_reminder = $cart->reminder_count + 1;

            // Check if enough time has passed for the next reminder
            $delay = $this->reminder_schedule[$next_reminder] ?? null;
            if ($delay === null) continue;

            $abandoned_time = strtotime($cart->created_at);
            $send_after     = $abandoned_time + $delay;

            if (time() < $send_after) continue; // Not time yet

            // Avoid double-sending: check last_reminder_at
            if ($cart->last_reminder_at && $next_reminder > 1) {
                $last_sent  = strtotime($cart->last_reminder_at);
                $min_gap    = ($next_reminder === 2) ? 72000 : 172800; // 20hr / 2day minimum gap
                if (time() - $last_sent < $min_gap) continue;
            }

            // Generate a discount code for 2nd and 3rd reminders
            $discount_code = $cart->discount_code;
            if (empty($discount_code) && $next_reminder >= 2) {
                $discount_code = 'COMEBACK' . strtoupper(substr(md5($cart->id . $cart->customer_email), 0, 6));
                $wpdb->update($this->table_name, ['discount_code' => $discount_code], ['id' => $cart->id]);
            }

            // Send the recovery email
            $this->send_recovery_email($cart, $next_reminder, $discount_code);

            // Update the cart record
            $wpdb->update($this->table_name, [
                'reminder_count'  => $next_reminder,
                'last_reminder_at'=> current_time('mysql', true),
                'status'          => 'reminded',
            ], ['id' => $cart->id]);

            $sent++;
        }

        if ($sent > 0) {
            error_log("[VMO Abandoned Cart] Sent {$sent} recovery email(s)");
        }
    }

    /**
     * Send a single recovery email
     */
    private function send_recovery_email($cart, $reminder_number, $discount_code = '') {
        $product_name  = esc_html($cart->product_name);
        $customer_name = !empty($cart->customer_name) ? esc_html($cart->customer_name) : 'there';
        $price         = strtoupper($cart->currency) . ' ' . number_format($cart->product_price, 2);

        // Build return-to-checkout URL
        $site_url    = home_url('/');
        $checkout_url = add_query_arg([
            'vmo_recover' => $cart->id,
            'product'     => $cart->product_id,
        ], $site_url);

        // Subject lines that escalate urgency
        $subjects = [
            1 => "You left something behind - {$product_name}",
            2 => "Still interested? Here's a special offer for {$product_name}",
            3 => "Last chance: Your reserved {$product_name} is about to go",
        ];
        $subject = $subjects[$reminder_number] ?? $subjects[1];

        // Build the email HTML
        $html = $this->build_recovery_email_html($cart, $reminder_number, $discount_code, $checkout_url, $customer_name, $product_name, $price);

        // Send via wp_mail
        $headers = ['Content-Type: text/html; charset=UTF-8'];
        $from_name  = get_bloginfo('name');
        $from_email = get_option('admin_email');
        $headers[]  = "From: {$from_name} <{$from_email}>";

        $result = wp_mail($cart->customer_email, $subject, $html, $headers);

        if ($result) {
            error_log("[VMO Abandoned Cart] Recovery email #{$reminder_number} sent to {$cart->customer_email} for cart #{$cart->id}");
        }

        return $result;
    }

    /**
     * Build beautiful recovery email HTML (matches VMO dark-theme design system)
     */
    private function build_recovery_email_html($cart, $reminder_number, $discount_code, $checkout_url, $customer_name, $product_name, $price) {
        // Color escalation based on reminder number
        $colors = [
            1 => ['gradient' => 'linear-gradient(135deg, #06b6d4, #8b5cf6)', 'accent' => '#06b6d4', 'label' => 'Did you forget something?'],
            2 => ['gradient' => 'linear-gradient(135deg, #f59e0b, #ef4444)', 'accent' => '#f59e0b', 'label' => 'Special offer just for you'],
            3 => ['gradient' => 'linear-gradient(135deg, #ef4444, #dc2626)', 'accent' => '#ef4444', 'label' => 'Last chance - expires soon'],
        ];
        $c = $colors[$reminder_number] ?? $colors[1];

        $discount_section = '';
        if (!empty($discount_code) && $reminder_number >= 2) {
            $discount_pct = ($reminder_number === 2) ? '10%' : '15%';
            $discount_section = '
            <div style="background:rgba(245,158,11,0.1); border:2px dashed #f59e0b; border-radius:12px; padding:20px; text-align:center; margin:20px 0;">
                <p style="margin:0 0 8px; font-size:14px; color:#fbbf24;">YOUR EXCLUSIVE DISCOUNT</p>
                <div style="font-size:36px; font-weight:800; color:#f59e0b; margin:8px 0;">' . esc_html($discount_pct) . ' OFF</div>
                <p style="margin:8px 0; font-size:13px; color:#94a3b8;">Use code at checkout:</p>
                <div style="background:#0f172a; border:1px solid #f59e0b; border-radius:8px; padding:10px 20px; display:inline-block; font-family:monospace; font-size:20px; font-weight:700; color:#fbbf24; letter-spacing:3px;">' . esc_html($discount_code) . '</div>
            </div>';
        }

        $urgency_bar = '';
        if ($reminder_number === 3) {
            $urgency_bar = '
            <div style="background:linear-gradient(90deg, #ef4444, #dc2626); padding:12px; text-align:center; font-size:13px; font-weight:600; color:white; letter-spacing:1px;">
                THIS OFFER EXPIRES IN 24 HOURS
            </div>';
        }

        return '<!DOCTYPE html>
<html>
<head><meta charset="UTF-8"><meta name="viewport" content="width=device-width, initial-scale=1.0"></head>
<body style="margin:0; padding:0; background-color:#0f172a; font-family:-apple-system, BlinkMacSystemFont, \'Segoe UI\', Roboto, sans-serif;">
<div style="max-width:600px; margin:0 auto; background-color:#1e293b; border-radius:16px; overflow:hidden; margin-top:20px; margin-bottom:20px; border:1px solid #334155;">

    ' . $urgency_bar . '

    <!-- Header -->
    <div style="background:' . $c['gradient'] . '; padding:40px 30px; text-align:center;">
        <div style="font-size:48px; margin-bottom:12px;">&#x1F6D2;</div>
        <h1 style="margin:0; color:white; font-size:24px; font-weight:700;">' . $c['label'] . '</h1>
    </div>

    <!-- Body -->
    <div style="padding:30px;">
        <p style="color:#e2e8f0; font-size:16px; line-height:1.6; margin:0 0 20px;">
            Hi ' . $customer_name . ',
        </p>
        <p style="color:#94a3b8; font-size:15px; line-height:1.6; margin:0 0 25px;">
            We noticed you were checking out <strong style="color:#e2e8f0;">' . $product_name . '</strong> but didn\'t complete your purchase. No worries &mdash; your item is still available.
        </p>

        <!-- Product Card -->
        <div style="background:#0f172a; border:1px solid #334155; border-radius:12px; padding:20px; margin:20px 0;">
            <div style="display:flex; justify-content:space-between; align-items:center;">
                <div>
                    <h3 style="margin:0 0 4px; color:#e2e8f0; font-size:16px;">' . $product_name . '</h3>
                    <p style="margin:0; color:#94a3b8; font-size:13px;">Ready to ship</p>
                </div>
                <div style="font-size:22px; font-weight:700; color:' . $c['accent'] . ';">' . $price . '</div>
            </div>
        </div>

        ' . $discount_section . '

        <!-- CTA Button -->
        <div style="text-align:center; margin:30px 0;">
            <a href="' . esc_url($checkout_url) . '" style="display:inline-block; background:' . $c['gradient'] . '; color:white; text-decoration:none; padding:16px 40px; border-radius:12px; font-size:16px; font-weight:700; letter-spacing:0.5px;">
                Complete Your Purchase &rarr;
            </a>
        </div>

        <p style="text-align:center; color:#64748b; font-size:12px; margin-top:25px;">
            If you have any questions, just reply to this email.<br>
            <a href="' . esc_url($checkout_url) . '" style="color:' . $c['accent'] . '; text-decoration:none;">Click here</a> to return to checkout.
        </p>
    </div>

    <!-- Footer -->
    <div style="padding:20px 30px; background:#0f172a; border-top:1px solid #334155; text-align:center;">
        <p style="margin:0; color:#475569; font-size:11px;">
            ' . esc_html(get_bloginfo('name')) . ' &bull; Powered by VMO AI Website Builder
        </p>
        <p style="margin:8px 0 0; color:#475569; font-size:10px;">
            <a href="' . esc_url(add_query_arg('vmo_unsubscribe', $cart->customer_email, home_url('/'))) . '" style="color:#475569; text-decoration:underline;">Unsubscribe</a>
        </p>
    </div>

</div>
</body>
</html>';
    }

    /**
     * Mark a cart as recovered when checkout completes
     * Called via do_action('vmo_checkout_completed', $order_id, $session_data)
     */
    public function mark_recovered($order_id, $session_data = []) {
        global $wpdb;

        $updated = $wpdb->update($this->table_name, [
            'status'       => 'recovered',
            'recovered_at' => current_time('mysql', true),
        ], [
            'order_id' => $order_id,
            'status'   => 'reminded', // Only mark reminded ones as recovered (for stats)
        ]);

        // Also check by session ID
        if (!$updated && !empty($session_data['session_id'])) {
            $wpdb->update($this->table_name, [
                'status'       => 'recovered',
                'recovered_at' => current_time('mysql', true),
            ], [
                'session_id' => $session_data['session_id'],
            ]);
        }
    }

    /**
     * Get abandoned cart statistics for the dashboard
     */
    public function get_stats($user_id = null) {
        global $wpdb;

        $where = '';
        if ($user_id) {
            $where = $wpdb->prepare(' AND user_id = %d', $user_id);
        }

        $stats = [
            'total_abandoned' => 0,
            'total_recovered' => 0,
            'recovery_rate'   => 0,
            'revenue_recovered' => 0,
            'pending_reminders' => 0,
            'last_30_days'    => [],
        ];

        // Total abandoned
        $stats['total_abandoned'] = (int) $wpdb->get_var(
            "SELECT COUNT(*) FROM {$this->table_name} WHERE 1=1 {$where}"
        );

        // Total recovered
        $stats['total_recovered'] = (int) $wpdb->get_var(
            "SELECT COUNT(*) FROM {$this->table_name} WHERE status = 'recovered' {$where}"
        );

        // Recovery rate
        if ($stats['total_abandoned'] > 0) {
            $stats['recovery_rate'] = round(($stats['total_recovered'] / $stats['total_abandoned']) * 100, 1);
        }

        // Revenue recovered
        $stats['revenue_recovered'] = (float) $wpdb->get_var(
            "SELECT COALESCE(SUM(product_price), 0) FROM {$this->table_name} WHERE status = 'recovered' {$where}"
        );

        // Pending reminders (abandoned/reminded with reminder_count < 3)
        $stats['pending_reminders'] = (int) $wpdb->get_var(
            "SELECT COUNT(*) FROM {$this->table_name} 
             WHERE status IN ('abandoned', 'reminded') 
             AND reminder_count < 3 {$where}"
        );

        // Last 30 days breakdown
        $thirty_days = $wpdb->get_results(
            "SELECT DATE(created_at) as date, 
                    COUNT(*) as abandoned,
                    SUM(CASE WHEN status = 'recovered' THEN 1 ELSE 0 END) as recovered
             FROM {$this->table_name}
             WHERE created_at >= DATE_SUB(NOW(), INTERVAL 30 DAY) {$where}
             GROUP BY DATE(created_at)
             ORDER BY date DESC"
        );
        $stats['last_30_days'] = $thirty_days ?: [];

        return $stats;
    }

    /**
     * Get recent abandoned carts for display
     */
    public function get_recent($limit = 10, $user_id = null) {
        global $wpdb;

        $where = '';
        if ($user_id) {
            $where = $wpdb->prepare(' AND user_id = %d', $user_id);
        }

        return $wpdb->get_results($wpdb->prepare(
            "SELECT * FROM {$this->table_name}
             WHERE 1=1 {$where}
             ORDER BY created_at DESC
             LIMIT %d",
            $limit
        ));
    }

    /**
     * Expire old abandoned carts (older than 30 days, never recovered)
     */
    public function expire_old_carts() {
        global $wpdb;

        $thirty_days_ago = gmdate('Y-m-d H:i:s', time() - (30 * 86400));

        $wpdb->update($this->table_name, [
            'status' => 'expired',
        ], [
            'status' => 'abandoned',
        ]);

        // Only expire those older than 30 days
        $wpdb->query($wpdb->prepare(
            "UPDATE {$this->table_name} 
             SET status = 'expired' 
             WHERE status = 'reminded' 
             AND reminder_count >= 3 
             AND created_at < %s",
            $thirty_days_ago
        ));
    }

    /**
     * Cleanup on plugin deactivation
     */
    public static function deactivate() {
        wp_clear_scheduled_hook('vmo_check_abandoned_carts');
        wp_clear_scheduled_hook('vmo_send_recovery_emails');
    }
}
