<?php
/**
 * Client-side event serialization.
 *
 * @package Carticy\Conversions\Client
 */

declare(strict_types=1);

namespace Carticy\Conversions\Client;

use Carticy\Conversions\Domain\ConversionEvent;
use Carticy\Conversions\Domain\ConversionEventType;

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

/**
 * Converts canonical order events into a provider-neutral dataLayer shape.
 */
final class ClientEventSerializer {

	/**
	 * Serialize a conversion event for browser delivery.
	 *
	 * @param ConversionEvent $event Event.
	 * @return array<string, mixed>
	 */
	public function serialize( ConversionEvent $event ): array {
		$data  = $event->to_array();
		$name  = $this->client_event_name( (string) $data['event_type'] );
		$value = is_array( $data['value'] ?? null ) ? $data['value'] : array();
		$items = $this->items( is_array( $data['items'] ?? null ) ? $data['items'] : array() );

		$payload = array(
			'event'          => $name,
			'event_id'       => (string) $data['event_id'],
			'transaction_id' => (string) $data['transaction_id'],
			'value'          => isset( $value['amount'] ) ? (float) $value['amount'] : 0.0,
			'currency'       => (string) ( $value['currency'] ?? '' ),
			'items'          => $items,
			'content_ids'    => array_values(
				array_filter(
					array_map(
						static function ( array $item ): string {
							return (string) ( $item['item_id'] ?? '' );
						},
						$items
					)
				)
			),
			'content_type'   => 'product',
			'affiliation'    => 'WooCommerce',
			'source'         => (string) ( $data['source'] ?? '' ),
			'occurred_at'    => (string) ( $data['occurred_at'] ?? '' ),
			'consent'        => $this->consent( is_array( $data['consent'] ?? null ) ? $data['consent'] : array() ),
		);

		if ( ConversionEventType::PURCHASE !== (string) $data['event_type'] ) {
			$payload['conversion_event_type'] = (string) $data['event_type'];
		}

		return $payload;
	}

	/**
	 * Map canonical server event types to browser event names.
	 *
	 * @param string $event_type Event type.
	 * @return string
	 */
	private function client_event_name( string $event_type ): string {
		if ( ConversionEventType::RENEWAL === $event_type ) {
			return 'purchase';
		}

		return $event_type;
	}

	/**
	 * Normalize event items.
	 *
	 * @param array<int, mixed> $items Raw items.
	 * @return array<int, array<string, mixed>>
	 */
	private function items( array $items ): array {
		$normalized = array();
		foreach ( $items as $item ) {
			if ( ! is_array( $item ) ) {
				continue;
			}

			$price        = is_array( $item['price'] ?? null ) ? $item['price'] : array();
			$normalized[] = array(
				'item_id'       => (string) ( $item['item_id'] ?? '' ),
				'item_name'     => (string) ( $item['name'] ?? '' ),
				'quantity'      => isset( $item['quantity'] ) ? max( 1, (int) $item['quantity'] ) : 1,
				'price'         => isset( $price['amount'] ) ? (float) $price['amount'] : 0.0,
				'currency'      => (string) ( $price['currency'] ?? '' ),
				'item_sku'      => (string) ( $item['sku'] ?? '' ),
				'item_category' => (string) ( $item['category'] ?? '' ),
				'item_variant'  => (string) ( $item['variant'] ?? '' ),
			);
		}

		return $normalized;
	}

	/**
	 * Normalize consent data for browser allow-list checks.
	 *
	 * @param array<string, mixed> $consent Consent snapshot.
	 * @return array<string, mixed>
	 */
	private function consent( array $consent ): array {
		$services = array();
		foreach ( is_array( $consent['services'] ?? null ) ? $consent['services'] : array() as $key => $state ) {
			$services[ sanitize_key( (string) $key ) ] = (string) $state;
		}

		return array(
			'state'    => (string) ( $consent['state'] ?? 'unset' ),
			'services' => $services,
		);
	}
}
