<?php
/**
 * WooCommerce e-commerce module.
 *
 * Two-phase, gateway-safe attribution:
 *  1) At checkout (customer's browser present) we resolve the visitor's
 *     last-touch source via the cookieless hash and store it on the order.
 *  2) When the order is actually paid (which may arrive via an off-site
 *     gateway webhook) we record revenue using the stored attribution.
 *
 * @package Defog
 */

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

class Defog_WooCommerce {

	public function __construct() {
		// Phase 1 — capture attribution while the buyer's request is in-flight.
		add_action( 'woocommerce_checkout_order_processed', array( $this, 'capture' ), 10, 1 );
		add_action( 'woocommerce_store_api_checkout_order_processed', array( $this, 'capture' ), 10, 1 );

		// Phase 2 — record revenue once paid (idempotent).
		add_action( 'woocommerce_payment_complete', array( $this, 'record' ), 10, 1 );
		add_action( 'woocommerce_order_status_processing', array( $this, 'record' ), 10, 1 );
		add_action( 'woocommerce_order_status_completed', array( $this, 'record' ), 10, 1 );

		// Funnel — add-to-cart action (customer's request is present).
		add_action( 'woocommerce_add_to_cart', array( $this, 'on_add_to_cart' ), 10, 0 );
	}

	/**
	 * Record an add-to-cart funnel signal for the current visitor.
	 */
	public function on_add_to_cart() {
		$ip   = Defog_Privacy::client_ip();
		$ua   = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
		$hash = Defog_Privacy::visitor_hash( $ip, $ua );
		defog_record_funnel( $hash, 'cart' );
	}

	/**
	 * Is WooCommerce active?
	 *
	 * @return bool
	 */
	public static function active() {
		return class_exists( 'WooCommerce' );
	}

	/**
	 * Resolve and store the last-touch attribution on the order.
	 *
	 * @param int|WC_Order $order Order id or object.
	 */
	public function capture( $order ) {
		$order = is_numeric( $order ) ? wc_get_order( $order ) : $order;
		if ( ! $order || ! is_a( $order, 'WC_Order' ) ) {
			return;
		}
		if ( $order->get_meta( '_defog_source' ) ) {
			return; // Already captured.
		}

		global $wpdb;
		$ip     = Defog_Privacy::client_ip();
		$ua     = isset( $_SERVER['HTTP_USER_AGENT'] ) ? sanitize_text_field( wp_unslash( $_SERVER['HTTP_USER_AGENT'] ) ) : '';
		$hash   = Defog_Privacy::visitor_hash( $ip, $ua );
		$events = defog_table( 'events' );

		// Country/device from the visitor's most recent event (any).
		$last = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT country, device FROM %i WHERE visitor_hash = %s ORDER BY occurred_at DESC LIMIT 1",
					$events,
				$hash
			)
		);

		// Source = the most recent NON-direct acquisition source. Internal cart /
		// checkout pageviews are classified 'direct', so plain last-touch would
		// always attribute the order to direct. Skipping 'direct' recovers the
		// real channel (paid / organic / social / …). To use first-touch instead,
		// change ORDER BY to occurred_at ASC.
		$source = $wpdb->get_var(
			$wpdb->prepare(
				"SELECT source FROM %i WHERE visitor_hash = %s AND source <> 'direct' ORDER BY occurred_at DESC LIMIT 1",
					$events,
				$hash
			)
		);

		$order->update_meta_data( '_defog_source', $source ? $source : 'direct' );
		$order->update_meta_data( '_defog_country', $last ? $last->country : Defog_Privacy::country() );
		$order->update_meta_data( '_defog_device', $last ? $last->device : 'desktop' );
		$order->update_meta_data( '_defog_vhash', $hash );
		$order->save();
	}

	/**
	 * Record a paid order into the analytics tables (once).
	 *
	 * @param int $order_id Order id.
	 */
	public function record( $order_id ) {
		$order = wc_get_order( $order_id );
		if ( ! $order || ! is_a( $order, 'WC_Order' ) ) {
			return;
		}
		if ( $order->get_meta( '_defog_recorded' ) ) {
			return; // Already recorded.
		}
		// Backfill attribution if checkout hook didn't run (e.g. admin order).
		if ( ! $order->get_meta( '_defog_source' ) ) {
			$this->capture( $order );
		}

		global $wpdb;

		$items = 0;
		foreach ( $order->get_items() as $item ) {
			$items += (int) $item->get_quantity();
		}

		$inserted = $wpdb->insert(
			defog_table( 'orders' ),
			array(
				'order_id'    => $order->get_id(),
				'occurred_at' => defog_now(),
				'total'       => (float) $order->get_total(),
				'currency'    => $order->get_currency(),
				'items'       => $items,
				'source'      => $order->get_meta( '_defog_source' ) ? $order->get_meta( '_defog_source' ) : 'direct',
				'country'     => $order->get_meta( '_defog_country' ) ? $order->get_meta( '_defog_country' ) : 'XX',
				'device'      => $order->get_meta( '_defog_device' ) ? $order->get_meta( '_defog_device' ) : 'desktop',
				'status'      => $order->get_status(),
			),
			array( '%d', '%s', '%f', '%s', '%d', '%s', '%s', '%s', '%s' )
		);

		// If the unique order_id already existed, stop (defensive double-guard).
		if ( false === $inserted ) {
			$order->update_meta_data( '_defog_recorded', 1 );
			$order->save();
			return;
		}

		$now = defog_now();
		foreach ( $order->get_items() as $item ) {
			$product = $item->get_product();
			$pid     = $product ? $product->get_id() : 0;
			$wpdb->insert(
				defog_table( 'order_items' ),
				array(
					'order_id'    => $order->get_id(),
					'product_id'  => $pid,
					'name'        => substr( $item->get_name(), 0, 190 ),
					'qty'         => (int) $item->get_quantity(),
					'total'       => (float) $item->get_total(),
					'occurred_at' => $now,
				),
				array( '%d', '%d', '%s', '%d', '%f', '%s' )
			);
		}

		$order->update_meta_data( '_defog_recorded', 1 );
		$order->save();

		// Funnel — purchase signal (using the hash captured at checkout).
		$vhash = $order->get_meta( '_defog_vhash' );
		if ( $vhash ) {
			defog_record_funnel( $vhash, 'purchase' );
		}
	}
}
