<?php

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

class AIEO_TikTok_Events_Sender {

	const ENDPOINT      = 'https://business-api.tiktok.com/open_api/v1.3/event/track/';
	const ASYNC_HOOK    = 'aieo_tiktok_send_purchase';
	const EVENT_ID_META = '_aieo_tt_event_id';
	const SENT_META     = '_aieo_tt_purchase_sent';
	const PLATFORM      = 'tiktok';

	
	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_session' ), 25, 2 );
		add_action( 'woocommerce_store_api_checkout_order_processed', array( $this, 'snapshot_session_block' ), 25, 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_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();
	}

	public static function resolve_credentials( array $config ) {
		return array(
			'pixel_id' => isset( $config['tiktok_pixel_id'] ) ? trim( (string) $config['tiktok_pixel_id'] ) : '',
			'token'    => isset( $config['tiktok_access_token'] ) ? trim( (string) $config['tiktok_access_token'] ) : '',
		);
	}

	private static function server_enabled( array $config ) {
		$mode = isset( $config['tiktok_mode'] ) ? $config['tiktok_mode'] : 'off';
		return in_array( $mode, array( 'server', 'both' ), 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_session( $order, $data = array() ) {
		unset( $data );
		$this->do_snapshot( $order );
	}
	public function snapshot_session_block( $order ) {
		$this->do_snapshot( $order );
	}
	private function do_snapshot( $order ) {
		if ( ! is_a( $order, 'WC_Order' ) ) {
			return;
		}
		if ( '' !== (string) $order->get_meta( '_aieo_attr_sid' ) ) {
			return; 
		}
		foreach ( array( 'aieo_attr_sid', 'aieo_session_id' ) as $ck ) {
			if ( ! empty( $_COOKIE[ $ck ] ) ) {
				$order->update_meta_data( '_aieo_attr_sid', sanitize_text_field( wp_unslash( $_COOKIE[ $ck ] ) ) );
				break;
			}
		}
	}

	
	
	

	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['pixel_id'] || '' === $creds['token'] ) {
			return;
		}
		$order = wc_get_order( $order_id );
		if ( ! $order || $order->get_meta( self::SENT_META ) ) {
			return;
		}
		self::get_or_mint_event_id( $order );
		$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 static function get_or_mint_event_id( $order ) {
		if ( ! is_a( $order, 'WC_Order' ) ) {
			return '';
		}
		$eid = (string) $order->get_meta( self::EVENT_ID_META );
		if ( '' === $eid ) {
			$eid = function_exists( 'wp_generate_uuid4' ) ? wp_generate_uuid4() : ( 'tt_' . md5( uniqid( (string) $order->get_id(), true ) ) );
			$order->update_meta_data( self::EVENT_ID_META, $eid );
			$order->save();
		}
		return $eid;
	}

	
	
	

	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['pixel_id'] || '' === $creds['token'] ) {
			return;
		}
		$order = wc_get_order( $order_id );
		if ( ! $order ) {
			return;
		}
		$eid = (string) $order->get_meta( self::EVENT_ID_META );
		if ( '' === $eid || $this->already_sent( $eid ) ) {
			return;
		}

		$test_code = isset( $config['tiktok_test_event_code'] ) ? trim( (string) $config['tiktok_test_event_code'] ) : '';
		$payload   = $this->build_payload( $order, $creds['pixel_id'], $test_code );

		
		
		
		
		$cfg_blocking = ( 'yes' === ( isset( $config['server_event_blocking'] ) ? $config['server_event_blocking'] : 'no' ) );
		$blocking = ( '' !== $test_code ) || (bool) apply_filters( 'aieo_server_event_blocking', $cfg_blocking, self::PLATFORM );
		$resp = wp_remote_post( self::ENDPOINT, array(
			'timeout'  => 6,
			'blocking' => $blocking,
			'headers'  => array(
				'Access-Token' => $creds['token'],
				'Content-Type' => 'application/json',
			),
			'body'     => wp_json_encode( $payload ),
		) );

		if ( $blocking ) {
			$this->log_result( $order, $eid, $payload, $resp, ( '' !== $test_code ) );
		} elseif ( function_exists( 'aieo_server_event_log_dispatched' ) ) {
			aieo_server_event_log_dispatched( self::PLATFORM, 'Purchase', $order, $eid );
		}
	}

	
	public function build_payload( $order, $pixel_code, $test_code = '' ) {
		$contents = 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();
			$contents[] = array(
				'content_id'   => (string) $pid,
				'content_type' => 'product',
				'content_name' => $item->get_name(),
				'quantity'     => $qty,
				'price'        => $qty > 0 ? round( (float) $item->get_total() / $qty, 2 ) : (float) $item->get_total(),
			);
		}

		$created    = $order->get_date_created();
		$event_time = $created ? $created->getTimestamp() : time();
		$source_url = method_exists( $order, 'get_checkout_order_received_url' ) ? $order->get_checkout_order_received_url() : home_url( '/' );

		$event = array(
			'event'      => 'Purchase', 
			'event_time' => (int) $event_time,
			'event_id'   => (string) $order->get_meta( self::EVENT_ID_META ),
			'user'       => $this->build_user( $order ),
			'page'       => array( 'url' => $source_url ),
			'properties' => array(
				'currency'     => $order->get_currency(),
				'value'        => (float) $order->get_total(),
				'content_type' => 'product',
				'contents'     => $contents,
			),
		);

		$body = array(
			'event_source'    => 'web',
			'event_source_id' => (string) $pixel_code,
			'data'            => array( $event ),
		);
		if ( '' !== $test_code ) {
			$body['test_event_code'] = $test_code;
		}
		return $body;
	}

	
	private function build_user( $order ) {
		$user = array();
		if ( class_exists( 'AIEO_PII_Hasher' ) ) {
			$em = AIEO_PII_Hasher::normalize_and_hash( 'em', (string) $order->get_billing_email() );
			$ph = AIEO_PII_Hasher::normalize_and_hash( 'ph', (string) $order->get_billing_phone() );
			if ( '' !== $em ) { $user['email'] = $em; }
			if ( '' !== $ph ) { $user['phone'] = $ph; }
		}
		$cust = (int) $order->get_customer_id();
		if ( $cust > 0 ) {
			$user['external_id'] = hash( 'sha256', (string) $cust );
		}
		$ttclid = $this->resolve_ttclid( $order );
		if ( '' !== $ttclid ) {
			$user['ttclid'] = $ttclid;
		}
		return $user;
	}

	
	private function resolve_ttclid( $order ) {
		$sid = (string) $order->get_meta( '_aieo_attr_sid' );
		if ( '' === $sid ) {
			return '';
		}
		global $wpdb;
		$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_tiktok' === ( $row['entry_channel'] ?? '' ) ) {
			return (string) $row['entry_click_id'];
		}
		return '';
	}

	
	
	

	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, $test_mode ) {
		if ( ! $this->table_ok() ) {
			return;
		}
		global $wpdb;
		$t = $this->table();

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

		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 );
			$decoded   = json_decode( $resp_body, true );
			$api_code  = ( is_array( $decoded ) && isset( $decoded['code'] ) ) ? (int) $decoded['code'] : -1;
			if ( is_array( $decoded ) && isset( $decoded['request_id'] ) ) {
				$trace = substr( (string) $decoded['request_id'], 0, 64 );
			}
			
			$status = ( $http_code >= 200 && $http_code < 300 && 0 === $api_code ) ? 'sent' : 'failed';
			if ( 'failed' === $status && is_array( $decoded ) && isset( $decoded['message'] ) ) {
				$err = substr( (string) $decoded['message'], 0, 255 );
			}
		}

		$now   = current_time( 'mysql', true );
		$props = isset( $payload['data'][0]['properties'] ) ? $payload['data'][0]['properties'] : 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, %d, %s, %s)
			 ON DUPLICATE KEY UPDATE
				status = VALUES(status), http_code = VALUES(http_code), fbtrace_id = VALUES(fbtrace_id),
				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,
			$trace,
			wp_json_encode( $payload ),
			substr( $resp_body, 0, 4000 ),
			$err,
			isset( $props['value'] ) ? (float) $props['value'] : 0,
			isset( $props['currency'] ) ? (string) $props['currency'] : '',
			$test_mode ? 1 : 0,
			$now,
			'sent' === $status ? $now : null
		) );
	}
}
