<?php

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

class AIEO_Google_Ads_EC_Sender {

	const TOKEN_ENDPOINT = 'https://oauth2.googleapis.com/token';
	const API_BASE       = 'https://googleads.googleapis.com/v17';
	const ASYNC_HOOK     = 'aieo_google_ads_ec_send';
	const GCLID_META     = '_aieo_gclid';
	const SENT_META      = '_aieo_google_ads_ec_sent';
	const PLATFORM       = 'google_ads';

	
	private static $instance = null;

	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' ), 22, 2 );
		add_action( 'woocommerce_store_api_checkout_order_processed', array( $this, 'snapshot_block' ), 22, 1 );
		add_action( 'woocommerce_payment_complete', array( $this, 'maybe_send' ), 22, 1 );
		add_action( 'woocommerce_order_status_processing', array( $this, 'maybe_send' ), 22, 1 );
		add_action( 'woocommerce_order_status_completed', array( $this, 'maybe_send' ), 22, 1 );
		add_action( self::ASYNC_HOOK, array( $this, 'send_conversion' ), 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();
	}

	
	public static function enabled( array $c ) {
		if ( ! isset( $c['ads_server_ec'] ) || 'yes' !== $c['ads_server_ec'] ) {
			return false;
		}
		foreach ( array( 'ads_developer_token', 'ads_customer_id', 'ads_oauth_client_id', 'ads_oauth_client_secret', 'ads_oauth_refresh_token', 'ads_conversion_action_id' ) as $k ) {
			if ( empty( $c[ $k ] ) ) {
				return false;
			}
		}
		return true;
	}

	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;
		}
		$gclid = $this->gclid_from_cookie();
		if ( '' === $gclid ) {
			$gclid = $this->gclid_from_session( $order );
		}
		if ( '' !== $gclid ) {
			$order->update_meta_data( self::GCLID_META, $gclid );
		}
	}

	
	private function gclid_from_cookie() {
		if ( ! empty( $_COOKIE['_gcl_aw'] ) ) {
			$raw   = sanitize_text_field( wp_unslash( $_COOKIE['_gcl_aw'] ) );
			$parts = explode( '.', $raw );
			if ( count( $parts ) >= 3 ) {
				return implode( '.', array_slice( $parts, 2 ) );
			}
		}
		if ( ! empty( $_GET['gclid'] ) ) {
			return sanitize_text_field( wp_unslash( $_GET['gclid'] ) );
		}
		return '';
	}

	
	private function gclid_from_session( $order ) {
		global $wpdb;
		$sid = '';
		foreach ( array( 'aieo_attr_sid', 'aieo_session_id' ) as $ck ) {
			if ( ! empty( $_COOKIE[ $ck ] ) ) {
				$sid = sanitize_text_field( wp_unslash( $_COOKIE[ $ck ] ) );
				break;
			}
		}
		if ( '' === $sid ) {
			return '';
		}
		$statics = $wpdb->prefix . 'aieo_sessions_statics';
		
		$row = $wpdb->get_row( $wpdb->prepare( "SELECT entry_click_id, entry_channel FROM `{$statics}` WHERE session_id = %s LIMIT 1", $sid ), ARRAY_A );
		if ( $row && ! empty( $row['entry_click_id'] ) && 'paid_google' === ( $row['entry_channel'] ?? '' ) ) {
			return (string) $row['entry_click_id'];
		}
		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::enabled( $config ) || self::consent_blocks() ) {
			return;
		}
		$order = wc_get_order( $order_id );
		if ( ! $order || $order->get_meta( self::SENT_META ) ) {
			return;
		}
		
		if ( '' === (string) $order->get_meta( self::GCLID_META ) ) {
			return;
		}
		$order->update_meta_data( self::SENT_META, 1 );
		$order->save();

		
		
		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_conversion( $order_id ) {
		$order_id = (int) $order_id;
		if ( $order_id <= 0 || ! function_exists( 'wc_get_order' ) ) {
			return;
		}
		$config = self::config();
		if ( ! self::enabled( $config ) || self::consent_blocks() ) {
			return;
		}
		$order = wc_get_order( $order_id );
		if ( ! $order ) {
			return;
		}
		$gclid = (string) $order->get_meta( self::GCLID_META );
		if ( '' === $gclid ) {
			return;
		}

		$token = $this->access_token( $config );
		if ( '' === $token ) {
			$this->log( $order, 'failed', 0, 'OAuth token request failed' );
			return;
		}

		$payload     = $this->build_payload( $order, $gclid, $config );
		$customer_id = preg_replace( '/[^0-9]/', '', (string) $config['ads_customer_id'] );
		$url         = self::API_BASE . '/customers/' . $customer_id . ':uploadClickConversions';

		$headers = array(
			'Authorization'   => 'Bearer ' . $token,
			'developer-token' => (string) $config['ads_developer_token'],
			'Content-Type'    => 'application/json',
		);
		if ( ! empty( $config['ads_login_customer_id'] ) ) {
			$headers['login-customer-id'] = preg_replace( '/[^0-9]/', '', (string) $config['ads_login_customer_id'] );
		}

		
		
		
		
		$cfg_blocking = ( 'yes' === ( isset( $config['server_event_blocking'] ) ? $config['server_event_blocking'] : 'no' ) );
		$blocking = (bool) apply_filters( 'aieo_server_event_blocking', $cfg_blocking, 'google_ads' );
		$resp = wp_remote_post( $url, array(
			'timeout'  => 10,
			'blocking' => $blocking,
			'headers'  => $headers,
			'body'     => wp_json_encode( $payload ),
		) );

		if ( ! $blocking ) {
			if ( function_exists( 'aieo_server_event_log_dispatched' ) ) {
				aieo_server_event_log_dispatched( 'google_ads', 'conversion', $order, (string) $order->get_id() );
			}
			return;
		}
		if ( is_wp_error( $resp ) ) {
			$this->log( $order, 'failed', 0, $resp->get_error_message() );
			return;
		}
		$code = (int) wp_remote_retrieve_response_code( $resp );
		$body = (string) wp_remote_retrieve_body( $resp );
		
		$status = ( $code >= 200 && $code < 300 && false === strpos( $body, 'partialFailureError' ) ) ? 'sent' : 'failed';
		$this->log( $order, $status, $code, $body );
	}

	
	private function access_token( array $c ) {
		$resp = wp_remote_post( self::TOKEN_ENDPOINT, array(
			'timeout' => 10,
			'body'    => array(
				'client_id'     => (string) $c['ads_oauth_client_id'],
				'client_secret' => (string) $c['ads_oauth_client_secret'],
				'refresh_token' => (string) $c['ads_oauth_refresh_token'],
				'grant_type'    => 'refresh_token',
			),
		) );
		if ( is_wp_error( $resp ) ) {
			return '';
		}
		$data = json_decode( (string) wp_remote_retrieve_body( $resp ), true );
		return ( is_array( $data ) && ! empty( $data['access_token'] ) ) ? (string) $data['access_token'] : '';
	}

	
	public function build_payload( $order, $gclid, array $c ) {
		$customer_id = preg_replace( '/[^0-9]/', '', (string) $c['ads_customer_id'] );
		$action_id   = preg_replace( '/[^0-9]/', '', (string) $c['ads_conversion_action_id'] );

		$dt   = $order->get_date_created();
		$when = $dt ? $dt->format( 'Y-m-d H:i:sP' ) : gmdate( 'Y-m-d H:i:s+00:00' );

		$ids = class_exists( 'AIEO_PII_Hasher' ) ? AIEO_PII_Hasher::google_ads_user_identifiers( $order ) : array();

		$conversion = array(
			'gclid'              => $gclid,
			'conversionAction'   => 'customers/' . $customer_id . '/conversionActions/' . $action_id,
			'conversionDateTime' => $when,
			'conversionValue'    => (float) $order->get_total(),
			'currencyCode'       => (string) $order->get_currency(),
			'orderId'            => (string) $order->get_id(),
		);
		if ( ! empty( $ids ) ) {
			$conversion['userIdentifiers'] = $ids;
		}

		
		
		
		
		if ( class_exists( 'AIEO_Consent' ) ) {
			$cs  = AIEO_Consent::ads_consent_for_order( $order );
			$map = array( 'granted' => 'GRANTED', 'denied' => 'DENIED', 'unspecified' => 'UNSPECIFIED' );
			$cv  = isset( $map[ $cs ] ) ? $map[ $cs ] : 'UNSPECIFIED';
			$conversion['consent'] = array(
				'adUserData'        => $cv,
				'adPersonalization' => $cv,
			);
		}

		return array(
			'conversions'    => array( $conversion ),
			'partialFailure' => true,
		);
	}

	
	
	

	private function log( $order, $status, $http_code, $response ) {
		global $wpdb;
		if ( ! function_exists( 'aieo_server_events_log_table' ) ) {
			return;
		}
		$t = aieo_server_events_log_table();
		if ( (string) $wpdb->get_var( $wpdb->prepare( 'SHOW TABLES LIKE %s', $t ) ) !== $t ) {
			return;
		}
		$resp = (string) $response;
		
		$wpdb->insert( $t, array(
			'platform'      => self::PLATFORM,
			'event_name'    => 'conversion',
			'event_id'      => (string) $order->get_id(),
			'order_id'      => (int) $order->get_id(),
			'status'        => $status,
			'http_code'     => (int) $http_code,
			'response_body' => mb_substr( $resp, 0, 2000 ),
			'error_message' => ( 'sent' !== $status ) ? mb_substr( $resp, 0, 255 ) : null,
			'value'         => (float) $order->get_total(),
			'currency'      => (string) $order->get_currency(),
			'created_at'    => current_time( 'mysql', true ),
			'sent_at'       => current_time( 'mysql', true ),
		) );
	}
}
