<?php
/**
 * Cart Abandonment Tracker
 *
 * Records cart snapshots when users add items and marks them as abandoned
 * if no order is completed within a configurable timeout.
 *
 * @package InsightPress
 */

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

class InsightPress_Cart_Tracker
{
    /**
     * Abandonment threshold in seconds (default: 1 hour).
     */
    const ABANDON_THRESHOLD = 3600;

    /**
     * DB table name (without prefix).
     */
    const TABLE_NAME = 'insightpress_abandoned_carts';

    /**
     * Constructor.
     */
    public function __construct()
    {
        // Create table on init
        add_action('init', array($this, 'maybe_create_table'));

        // Track cart changes
        add_action('woocommerce_add_to_cart',        array($this, 'snapshot_cart'), 10, 6);
        add_action('woocommerce_cart_item_removed',   array($this, 'snapshot_cart'), 10, 2);
        add_action('woocommerce_cart_item_restored',  array($this, 'snapshot_cart'), 10, 2);
        add_action('woocommerce_after_cart_item_quantity_update', array($this, 'snapshot_cart'), 10, 4);

        // Mark as converted when order is placed
        add_action('woocommerce_checkout_order_created',          array($this, 'mark_converted'), 10, 1);
        add_action('woocommerce_store_api_checkout_order_processed', array($this, 'mark_converted'), 10, 1);

        // Hourly cron to mark old active carts as abandoned
        add_action('insightpress_mark_abandoned_carts', array($this, 'mark_abandoned_carts'));
        if (!wp_next_scheduled('insightpress_mark_abandoned_carts')) {
            wp_schedule_event(time(), 'hourly', 'insightpress_mark_abandoned_carts');
        }
    }

    /**
     * Create DB table if it doesn't exist yet.
     */
    public function maybe_create_table()
    {
        global $wpdb;
        $table = $wpdb->prefix . self::TABLE_NAME;

        if ($wpdb->get_var("SHOW TABLES LIKE '$table'") === $table) {
            return; // Already exists
        }

        $charset_collate = $wpdb->get_charset_collate();

        $sql = "CREATE TABLE $table (
            id BIGINT(20) UNSIGNED NOT NULL AUTO_INCREMENT,
            session_id VARCHAR(255) NOT NULL,
            user_id BIGINT(20) UNSIGNED DEFAULT 0,
            user_email VARCHAR(255) DEFAULT '',
            cart_contents LONGTEXT NOT NULL,
            cart_total DECIMAL(10,2) DEFAULT 0,
            item_count INT(11) DEFAULT 0,
            status VARCHAR(20) DEFAULT 'active',
            created_at DATETIME DEFAULT CURRENT_TIMESTAMP,
            updated_at DATETIME DEFAULT CURRENT_TIMESTAMP ON UPDATE CURRENT_TIMESTAMP,
            PRIMARY KEY (id),
            UNIQUE KEY session_id (session_id),
            KEY status (status),
            KEY updated_at (updated_at)
        ) $charset_collate;";

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

    /**
     * Get the current session identifier.
     */
    protected function get_session_id()
    {
        if (is_user_logged_in()) {
            return 'user_' . get_current_user_id();
        }

        // Use WooCommerce session cookie
        if (isset(WC()->session)) {
            $session_key = WC()->session->get_customer_id();
            if ($session_key) {
                return 'session_' . $session_key;
            }
        }

        // Fallback to PHP session ID
        if (!session_id()) {
            @session_start();
        }
        return 'php_' . session_id();
    }

    /**
     * Snapshot the current cart state to the DB.
     * Called generically — WooCommerce hooks pass varying args but we ignore them.
     */
    public function snapshot_cart(...$args)
    {
        if (!WC()->cart) {
            return;
        }

        // Delay slightly so cart updates are reflected
        add_action('woocommerce_cart_updated', array($this, 'do_snapshot'));
    }

    /**
     * Perform the actual cart snapshot write.
     */
    public function do_snapshot()
    {
        global $wpdb;

        if (!WC()->cart || WC()->cart->is_empty()) {
            return;
        }

        $session_id    = $this->get_session_id();
        $user_id       = get_current_user_id();
        $user_email    = $user_id ? get_userdata($user_id)->user_email : '';
        $cart_contents = wp_json_encode(WC()->cart->get_cart_contents());
        $cart_total    = (float) WC()->cart->get_cart_contents_total();
        $item_count    = (int) WC()->cart->get_cart_contents_count();
        $table         = $wpdb->prefix . self::TABLE_NAME;

        $wpdb->replace(
            $table,
            array(
                'session_id'    => $session_id,
                'user_id'       => $user_id,
                'user_email'    => $user_email,
                'cart_contents' => $cart_contents,
                'cart_total'    => $cart_total,
                'item_count'    => $item_count,
                'status'        => 'active',
                'updated_at'    => current_time('mysql'),
            ),
            array('%s', '%d', '%s', '%s', '%f', '%d', '%s', '%s')
        );
    }

    /**
     * Mark a session's cart as converted when an order is completed.
     */
    public function mark_converted($order)
    {
        global $wpdb;

        $session_id = $this->get_session_id();
        $table      = $wpdb->prefix . self::TABLE_NAME;

        $wpdb->update(
            $table,
            array('status' => 'converted'),
            array('session_id' => $session_id),
            array('%s'),
            array('%s')
        );
    }

    /**
     * Cron job: mark active carts not updated in ABANDON_THRESHOLD seconds as abandoned.
     */
    public function mark_abandoned_carts()
    {
        global $wpdb;

        $threshold = gmdate('Y-m-d H:i:s', time() - self::ABANDON_THRESHOLD);
        $table     = $wpdb->prefix . self::TABLE_NAME;

        $wpdb->query(
            $wpdb->prepare(
                "UPDATE $table SET status = 'abandoned' WHERE status = 'active' AND updated_at < %s",
                $threshold
            )
        );
    }

    /**
     * Get the full table name.
     */
    public static function get_table_name()
    {
        global $wpdb;
        return $wpdb->prefix . self::TABLE_NAME;
    }
}
