<?php

declare(strict_types=1);

namespace Numinix\SeekmodoWordPress\Commerce;

use Numinix\SeekmodoWordPress\Events\EventsQueue;
use Numinix\SeekmodoWordPress\Gateway\ShopperContext;

/**
 * WooCommerce add-to-cart and purchase mirroring for LTR + funnel analytics.
 */
final class ConversionEvents
{
    public static function register(): void
    {
        if (!function_exists('add_action') || !class_exists('WooCommerce', false)) {
            return;
        }

        add_action('woocommerce_add_to_cart', [self::class, 'onAddToCart'], 20, 6);
        // thankyou alone misses redirect/gateway checkouts that never render
        // the order-received page; payment_complete covers those.
        add_action('woocommerce_thankyou', [self::class, 'onThankYou'], 20, 1);
        add_action('woocommerce_payment_complete', [self::class, 'onPaymentComplete'], 20, 1);
    }

    /**
     * @param int|string $cart_item_key
     */
    public static function onAddToCart(
        $cart_item_key,
        int $product_id,
        int $quantity,
        int $variation_id,
        array $variation,
        array $cart_item_data
    ): void {
        if (!function_exists('numinix_seekmodo_can_index') || !numinix_seekmodo_can_index()) {
            return;
        }
        // Session restore re-fires woocommerce_add_to_cart for every
        // line item. Those are not shopper intent and previously
        // flooded the events queue (POCO: ~500k ATC/day, flush wedged).
        // That skip alone is the storm guard — do not require REQUEST
        // fingerprints (theme/custom AJAX often omits add-to-cart keys).
        if (function_exists('doing_action') && doing_action('woocommerce_load_cart_from_session')) {
            return;
        }
        $objectId = $variation_id > 0 ? $variation_id : $product_id;
        if ($objectId <= 0) {
            return;
        }

        EventsQueue::push([
            'type'        => 'add_to_cart',
            'object_id'   => $objectId,
            'keyword'     => self::resolveKeyword(),
            'position'    => 0,
            'surface'     => 'cart',
            'object_type' => 'product',
            'occurred_at' => time(),
            'session_id'  => ShopperContext::sessionId(),
            'ua'          => ShopperContext::userAgent(),
            'ip'          => ShopperContext::clientIp(),
            'qty'         => max(1, $quantity),
        ]);
    }

    public static function onThankYou($order_id): void
    {
        self::emitPurchase((int) $order_id);
    }

    public static function onPaymentComplete($order_id): void
    {
        self::emitPurchase((int) $order_id);
    }

    private static function emitPurchase(int $order_id): void
    {
        if (!function_exists('numinix_seekmodo_can_index') || !numinix_seekmodo_can_index()) {
            return;
        }
        if ($order_id <= 0 || !function_exists('wc_get_order')) {
            return;
        }
        // Dedupe thankyou + payment_complete for the same order.
        if (function_exists('get_transient') && function_exists('set_transient')) {
            $key = 'seekmodo_wp_purchase_emitted_' . $order_id;
            if (get_transient($key)) {
                return;
            }
            $ttl = defined('DAY_IN_SECONDS') ? (int) DAY_IN_SECONDS : 86400;
            set_transient($key, 1, $ttl);
        }

        $order = wc_get_order($order_id);
        if (!$order) {
            return;
        }

        $keyword = self::resolveKeyword();
        $sessionId = ShopperContext::sessionId();
        $ua = ShopperContext::userAgent();
        $ip = ShopperContext::clientIp();

        foreach ($order->get_items() as $item) {
            if (!is_object($item) || !method_exists($item, 'get_product_id')) {
                continue;
            }
            $productId = (int) $item->get_product_id();
            if ($productId <= 0) {
                continue;
            }
            $qty = method_exists($item, 'get_quantity') ? max(1, (int) $item->get_quantity()) : 1;
            $lineTotal = method_exists($item, 'get_total') ? (float) $item->get_total() : 0.0;
            $unitPrice = $qty > 0 ? $lineTotal / $qty : $lineTotal;

            EventsQueue::push([
                'type'        => 'purchase',
                'object_id'   => $productId,
                'keyword'     => $keyword,
                'position'    => 0,
                'surface'     => 'checkout',
                'object_type' => 'product',
                'occurred_at' => time(),
                'session_id'  => $sessionId,
                'ua'          => $ua,
                'ip'          => $ip,
                'qty'         => $qty,
                'price'       => $unitPrice,
                'order_id'    => $order_id,
            ]);
        }
    }

    private static function resolveKeyword(): string
    {
        if (function_exists('get_search_query')) {
            $kw = trim((string) get_search_query(false));
            if ($kw !== '') {
                return substr($kw, 0, 255);
            }
        }
        if (isset($_GET['s']) && is_string($_GET['s'])) {
            $kw = trim($_GET['s']);
            if ($kw !== '') {
                return substr($kw, 0, 255);
            }
        }

        return '';
    }
}
