<?php

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

class AIEO_GA4_Sender {

	const ENDPOINT    = 'https://www.google-analytics.com/mp/collect';
	const ASYNC_HOOK  = 'aieo_ga4_send_purchase';
	const CID_META    = '_aieo_ga_cid';
	const SENT_META   = '_aieo_ga4_purchase_sent';
	const PLATFORM    = 'ga4';

	
	private static $instance = null;

	
	private static $enqueued = array();

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

	public function register_hooks() {
		add_action( 'woocommerce_checkout_create_order', array( $this, 'snapshot' ), 21, 2 );
		add_action( 'woocommerce_store_api_checkout_order_processed', array( $this, 'snapshot_block' ), 21, 1 );
		add_action( 'woocommerce_payment_complete', array( $this, 'maybe_send' ), 21, 1 );
		add_action( 'woocommerce_order_status_processing', array( $this, 'maybe_send' ), 21, 1 );
		add_action( 'woocommerce_order_status_completed', array( $this, 'maybe_send' ), 21, 1 );
		add_action( self::ASYNC_HOOK, array( $this, 'send_purchase' ), 10, 1 );
	}

	
	
	

	public static function config() {
		if ( class_exists( 'AIEO_DMM_Conversions' ) && method_exists( 'AIEO_DMM_Conversions', 'get_config' ) ) {
			return AIEO_DMM_Conversions::get_config();
		}
		$o = get_option( 'aieo_dmm_conversions', array() );
		return is_array( $o ) ? $o : array();
	}

	
	private static function server_enabled( array $config ) {
		$source = isset( $config['ga_source'] ) ? $config['ga_source'] : 'off';
		$server = isset( $config['ga_send_server'] ) ? $config['ga_send_server'] : 'no';
		return ( 'aieo' === $source && 'yes' === $server );
	}

	public static function resolve_credentials( array $config ) {
		return array(
			'measurement_id' => isset( $config['ga_measurement_id'] ) ? trim( (string) $config['ga_measurement_id'] ) : '',
			'api_secret'     => isset( $config['ga_api_secret'] ) ? trim( (string) $config['ga_api_secret'] ) : '',
		);
	}

	private static function consent_blocks() {
		if ( ! class_exists( 'AIEO_Session_Tracker' ) ) {
			return false;
		}
		
		if ( method_exists( 'AIEO_Session_Tracker', 'is_marketing_consent_blocking' ) ) {
			return AIEO_Session_Tracker::is_marketing_consent_blocking();
		}
		if ( method_exists( 'AIEO_Session_Tracker', 'is_consent_blocking_writes' ) ) {
			return AIEO_Session_Tracker::is_consent_blocking_writes();
		}
		return false;
	}

	
	
	

	public function snapshot( $order, $data = array() ) {
		unset( $data );
		$this->do_snapshot( $order );
	}

	public function snapshot_block( $order ) {
		$this->do_snapshot( $order );
	}

	
	private function do_snapshot( $order ) {
		if ( ! is_a( $order, 'WC_Order' ) ) {
			return;
		}
		$cid = $this->client_id_from_cookie();
		if ( '' !== $cid ) {
			$order->update_meta_data( self::CID_META, $cid );
		}
	}

	
	private function client_id_from_cookie() {
		if ( empty( $_COOKIE['_ga'] ) ) {
			return '';
		}
		$raw   = sanitize_text_field( wp_unslash( $_COOKIE['_ga'] ) );
		$parts = explode( '.', $raw );
		
		if ( count( $parts ) >= 4 ) {
			return $parts[ count( $parts ) - 2 ] . '.' . $parts[ count( $parts ) - 1 ];
		}
		return '';
	}

	public function maybe_send( $order_id ) {
		$order_id = (int) $order_id;
		if ( $order_id <= 0 || ! function_exists( 'wc_get_order' ) ) {
			return;
		}
		$config = self::config();
		if ( ! self::server_enabled( $config ) || self::consent_blocks() ) {
			return;
		}
		$creds = self::resolve_credentials( $config );
		if ( '' === $creds['measurement_id'] || '' === $creds['api_secret'] ) {
			return;
		}
		$order = wc_get_order( $order_id );
		if ( ! $order || $order->get_meta( self::SENT_META ) ) {
			return; 
		}
		
		if ( isset( self::$enqueued[ $order_id ] ) ) {
			return;
		}
		self::$enqueued[ $order_id ] = true;
		
		

		
		
		if ( function_exists( 'aieo_server_event_dispatch' ) ) {
			aieo_server_event_dispatch( self::ASYNC_HOOK, $order_id );
		} elseif ( function_exists( 'as_enqueue_async_action' ) ) {
			as_enqueue_async_action( self::ASYNC_HOOK, array( $order_id ), 'aieo-server-events' );
		} else {
			wp_schedule_single_event( time() + 1, self::ASYNC_HOOK, array( $order_id ) );
		}
	}

	
	
	

	public function send_purchase( $order_id ) {
		$order_id = (int) $order_id;
		if ( $order_id <= 0 || ! function_exists( 'wc_get_order' ) ) {
			return;
		}
		$config = self::config();
		if ( ! self::server_enabled( $config ) || self::consent_blocks() ) {
			return;
		}
		$creds = self::resolve_credentials( $config );
		if ( '' === $creds['measurement_id'] || '' === $creds['api_secret'] ) {
			return;
		}
		$order = wc_get_order( $order_id );
		if ( ! $order ) {
			return;
		}
		if ( $this->already_sent( (string) $order_id ) ) {
			return;
		}

		$body = $this->build_mp_payload( $order );

		$url = add_query_arg(
			array(
				'measurement_id' => rawurlencode( $creds['measurement_id'] ),
				'api_secret'     => rawurlencode( $creds['api_secret'] ),
			),
			self::ENDPOINT
		);

		
		
		
		
		
		$blocking = (bool) apply_filters( 'aieo_server_event_blocking', true, 'ga4' );
		$resp = wp_remote_post( $url, array(
			'timeout'  => 6,
			'blocking' => $blocking,
			'headers'  => array( 'Content-Type' => 'application/json' ),
			'body'     => wp_json_encode( $body ),
		) );

		if ( $blocking ) {
			$sent = $this->log_result( $order, (string) $order_id, $body, $resp );
			
			if ( $sent ) {
				$order->update_meta_data( self::SENT_META, 1 );
				$order->save();
			}
		} elseif ( function_exists( 'aieo_server_event_log_dispatched' ) ) {
			aieo_server_event_log_dispatched( 'ga4', 'purchase', $order, (string) $order_id );
		}
	}

	
	public function build_mp_payload( $order ) {
		$cid = (string) $order->get_meta( self::CID_META );
		if ( '' === $cid ) {
			
			$cid = sprintf( '%d.%d', crc32( 'aieo' . $order->get_id() ) & 0x7fffffff, (int) ( $order->get_date_created() ? $order->get_date_created()->getTimestamp() : time() ) );
		}

		$items = array();
		foreach ( $order->get_items() as $item ) {
			if ( ! is_a( $item, 'WC_Order_Item_Product' ) ) {
				continue;
			}
			$pid   = $item->get_variation_id() ? (int) $item->get_variation_id() : (int) $item->get_product_id();
			$qty   = (int) $item->get_quantity();
			$prod  = $item->get_product();
			$items[] = array(
				'item_id'   => (string) $pid,
				'item_name' => (string) $item->get_name(),
				'quantity'  => $qty,
				'price'     => $qty > 0 ? round( (float) $item->get_total() / $qty, 2 ) : (float) $item->get_total(),
			);
		}

		$event = array(
			'name'   => 'purchase',
			'params' => array(
				'currency'       => $order->get_currency(),
				'value'          => (float) $order->get_total(),
				'transaction_id' => (string) $order->get_id(),
				'items'          => $items,
			),
		);

		$body = array(
			'client_id' => $cid,
			'events'    => array( $event ),
		);

		
		
		
		
		
		if ( class_exists( 'AIEO_Consent' ) ) {
			$cs = AIEO_Consent::ads_consent_for_order( $order );
			if ( 'granted' === $cs || 'denied' === $cs ) {
				$g = ( 'granted' === $cs ) ? 'GRANTED' : 'DENIED';
				$body['consent'] = array(
					'ad_user_data'       => $g,
					'ad_personalization' => $g,
				);
			}
		}

		
		
		
		
		if ( class_exists( 'AIEO_PII_Hasher' ) ) {
			$ud    = array();
			$email = AIEO_PII_Hasher::normalize_and_hash( 'em', (string) $order->get_billing_email() );
			$phone = AIEO_PII_Hasher::normalize_and_hash( 'ph', (string) $order->get_billing_phone() );
			if ( '' !== $email ) { $ud['sha256_email_address'] = $email; }
			if ( '' !== $phone ) { $ud['sha256_phone_number'] = $phone; }

			$addr   = array();
			$fn     = AIEO_PII_Hasher::normalize_and_hash( 'fn', (string) $order->get_billing_first_name() );
			$ln     = AIEO_PII_Hasher::normalize_and_hash( 'ln', (string) $order->get_billing_last_name() );
			$street = AIEO_PII_Hasher::normalize_and_hash( 'street', trim( $order->get_billing_address_1() . ' ' . $order->get_billing_address_2() ) );
			if ( '' !== $fn )     { $addr['sha256_first_name'] = $fn; }
			if ( '' !== $ln )     { $addr['sha256_last_name'] = $ln; }
			if ( '' !== $street ) { $addr['sha256_street'] = $street; }
			$city    = AIEO_PII_Hasher::lc( $order->get_billing_city() );
			$region  = AIEO_PII_Hasher::lc( $order->get_billing_state() );
			$postal  = AIEO_PII_Hasher::lc( $order->get_billing_postcode() );
			$country = AIEO_PII_Hasher::lc( $order->get_billing_country() );
			if ( '' !== $city )    { $addr['city'] = $city; }
			if ( '' !== $region )  { $addr['region'] = $region; }
			if ( '' !== $postal )  { $addr['postal_code'] = $postal; }
			if ( '' !== $country ) { $addr['country'] = $country; }
			if ( ! empty( $addr ) ) {
				$ud['address'] = array( $addr );
			}

			if ( ! empty( $ud ) ) {
				$body['user_data'] = $ud;
			}
		}

		$cust = (int) $order->get_customer_id();
		if ( $cust > 0 ) {
			$body['user_id'] = (string) $cust;
		}

		return $body;
	}

	
	
	

	private function table() {
		global $wpdb;
		return $wpdb->prefix . 'aieo_server_events_log';
	}

	private function table_ok() {
		global $wpdb;
		static $ok = null;
		if ( null === $ok ) {
			$t  = $this->table();
			$ok = ( (string) $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $t ) ) === $t );
		}
		return $ok;
	}

	private function already_sent( $event_id ) {
		if ( ! $this->table_ok() ) {
			return false;
		}
		global $wpdb;
		$t = $this->table();
		
		return (bool) $wpdb->get_var( $wpdb->prepare(
			"SELECT 1 FROM `{$t}` WHERE event_id = %s AND platform = %s AND status = 'sent' LIMIT 1",
			$event_id, self::PLATFORM
		) );
	}

	private function log_result( $order, $event_id, $payload, $resp ) {
		if ( ! $this->table_ok() ) {
			
			$code = is_wp_error( $resp ) ? 0 : (int) wp_remote_retrieve_response_code( $resp );
			return ( $code >= 200 && $code < 300 );
		}
		global $wpdb;
		$t = $this->table();

		$http_code = null;
		$resp_body = '';
		$status    = 'failed';
		$err       = null;

		if ( is_wp_error( $resp ) ) {
			$err = substr( $resp->get_error_message(), 0, 255 );
		} else {
			$http_code = (int) wp_remote_retrieve_response_code( $resp );
			$resp_body = (string) wp_remote_retrieve_body( $resp );
			
			$status = ( $http_code >= 200 && $http_code < 300 ) ? 'sent' : 'failed';
		}

		$now    = current_time( 'mysql', true );
		$params = isset( $payload['events'][0]['params'] ) ? $payload['events'][0]['params'] : array();

		
		$wpdb->query( $wpdb->prepare(
			"INSERT INTO `{$t}`
				(event_id, platform, event_name, order_id, session_id, user_id, status, http_code, fbtrace_id,
				 attempts, request_payload, response_body, error_message, value, currency, test_mode, created_at, sent_at)
			 VALUES (%s, %s, %s, %d, %s, %d, %s, %d, %s, 1, %s, %s, %s, %f, %s, 0, %s, %s)
			 ON DUPLICATE KEY UPDATE
				status = VALUES(status), http_code = VALUES(http_code), attempts = attempts + 1,
				request_payload = VALUES(request_payload), response_body = VALUES(response_body),
				error_message = VALUES(error_message), sent_at = VALUES(sent_at)",
			$event_id,
			self::PLATFORM,
			'purchase',
			(int) $order->get_id(),
			(string) $order->get_meta( '_aieo_attr_sid' ),
			(int) $order->get_customer_id(),
			$status,
			null === $http_code ? 0 : $http_code,
			'',
			wp_json_encode( $payload ),
			substr( $resp_body, 0, 4000 ),
			null === $err ? '' : $err,
			isset( $params['value'] ) ? (float) $params['value'] : 0,
			isset( $params['currency'] ) ? (string) $params['currency'] : '',
			$now,
			'sent' === $status ? $now : null
		) );

		return 'sent' === $status;
	}
}
