<?php
/**
 * Syncs a WooCommerce order to Attio CRM as a note on the person record
 *
 * @package WooAttioSync
 */

declare( strict_types=1 );

defined( 'ABSPATH' ) || exit;

/**
 * Handles syncing a single WooCommerce order to Attio
 */
class WooAttioSync_Sync_Order {

	private WooAttioSync_Attio_Client $client;

	public function __construct( WooAttioSync_Attio_Client $client ) {
		$this->client = $client;
	}

	/**
	 * Syncs an order to Attio — upserts the person, then creates a note
	 *
	 * Skips note creation if the order was already synced to avoid duplicate notes
	 * on subscription renewals or repeated status transitions.
	 *
	 * @param int $order_id WooCommerce order ID.
	 * @return array|WP_Error Attio note record on success, WP_Error on failure.
	 */
	public function sync( int $order_id ): array|WP_Error {
		$order = wc_get_order( $order_id );

		if ( ! $order ) {
			$error = new WP_Error( 'order_not_found', sprintf( 'Order %d not found', $order_id ), array( 'status' => 404 ) );
			WooAttioSync_Sync_Log::log( 'order', (string) $order_id, 'error', $error->get_error_message() );
			return $error;
		}

		$customer_sync = new WooAttioSync_Sync_Customer( $this->client );
		$person_result = $customer_sync->sync( $order_id, 'order' );

		if ( is_wp_error( $person_result ) ) {
			return $person_result;
		}

		$attio_record_id = $person_result['data']['id']['record_id'] ?? '';

		if ( empty( $attio_record_id ) ) {
			$error = new WP_Error( 'missing_record_id', 'Attio person sync succeeded but returned no record ID', array( 'status' => 422 ) );
			WooAttioSync_Sync_Log::log( 'order', (string) $order_id, 'error', $error->get_error_message() );
			return $error;
		}

		$existing_note_id = $order->get_meta( '_wcattio_note_id', true );
		if ( ! empty( $existing_note_id ) ) {
			WooAttioSync_Sync_Log::log( 'order', (string) $order_id, 'success', '', $existing_note_id );
			return array( 'data' => array( 'id' => array( 'note_id' => $existing_note_id ) ) );
		}

		[ $title, $content ] = $this->build_note( $order );

		$result = $this->client->create_note( 'people', $attio_record_id, $title, $content );

		if ( is_wp_error( $result ) ) {
			WooAttioSync_Sync_Log::log( 'order', (string) $order_id, 'error', $result->get_error_message(), $attio_record_id );
			return $result;
		}

		$note_id = $result['data']['id']['note_id'] ?? '';
		if ( '' !== $note_id ) {
			// Store the note ID so re-syncs skip creation
			$order->update_meta_data( '_wcattio_note_id', $note_id );
			$order->save_meta_data();
		}

		WooAttioSync_Sync_Log::log( 'order', (string) $order_id, 'success', '', $note_id );

		return $result;
	}

	/**
	 * Builds the note title and body for an order
	 *
	 * @param WC_Order $order The WooCommerce order.
	 * @return array{0: string, 1: string} Tuple of [title, content].
	 */
	private function build_note( WC_Order $order ): array {
		$order_number = $order->get_order_number();
		// Strip HTML tags and decode entities from the formatted total for plaintext output
		$formatted_total = html_entity_decode(
			wp_strip_all_tags( $order->get_formatted_order_total() ),
			ENT_QUOTES | ENT_HTML5
		);

		$title = sprintf( 'Order #%s - %s', $order_number, $formatted_total );

		$order_date   = $order->get_date_created();
		$date_string  = $order_date ? $order_date->date_i18n( 'Y-m-d' ) : '';
		$status_label = wc_get_order_status_name( $order->get_status() );

		$lines = array(
			sprintf( 'Order #%s', $order_number ),
		);

		if ( $date_string ) {
			$lines[] = sprintf( 'Date: %s', $date_string );
		}

		$lines[] = sprintf( 'Status: %s', $status_label );
		$lines[] = sprintf( 'Total: %s', $formatted_total );

		$items = $order->get_items( 'line_item' );
		if ( ! empty( $items ) ) {
			$lines[] = '';
			$lines[] = 'Items:';
			foreach ( $items as $item ) {
				/** @var WC_Order_Item_Product $item */
				$name     = $item->get_name();
				$quantity = (int) $item->get_quantity();
				$lines[]  = sprintf( '- %s x%d', $name, $quantity );
			}
		}

		$summary = $this->customer_summary( $order );
		if ( '' !== $summary ) {
			$lines[] = '';
			$lines[] = $summary;
		}

		$content = implode( "\n", $lines );

		return array( $title, $content );
	}

	/**
	 * Build a one-line lifetime-value summary of the customer behind an order, so
	 * every synced note doubles as a customer snapshot in Attio (order count,
	 * lifetime spend, average order value, and how long they have been a customer).
	 *
	 * @param WC_Order $order The order whose customer to summarize.
	 * @return string Summary line, or '' when history cannot be determined.
	 */
	private function customer_summary( WC_Order $order ): string {
		$stats = WooAttioSync_Customer_Stats::for_email( $order->get_billing_email() );
		if ( 0 === $stats['count'] ) {
			return '';
		}

		$money = static fn( float $n ): string => html_entity_decode( wp_strip_all_tags( wc_price( $n ) ), ENT_QUOTES | ENT_HTML5 );

		$parts = array(
			/* translators: %d: number of paid orders the customer has placed */
			sprintf( _n( '%d order', '%d orders', $stats['count'], 'harbor-sync-with-attio-for-woocommerce' ), $stats['count'] ),
			/* translators: %s: formatted lifetime spend */
			sprintf( __( '%s lifetime', 'harbor-sync-with-attio-for-woocommerce' ), $money( $stats['total'] ) ),
			/* translators: %s: formatted average order value */
			sprintf( __( 'avg %s', 'harbor-sync-with-attio-for-woocommerce' ), $money( $stats['average'] ) ),
		);
		if ( '' !== $stats['first_date'] ) {
			/* translators: %s: date the customer first ordered (Y-m-d) */
			$parts[] = sprintf( __( 'since %s', 'harbor-sync-with-attio-for-woocommerce' ), $stats['first_date'] );
		}

		return __( 'Customer:', 'harbor-sync-with-attio-for-woocommerce' ) . ' ' . implode( ' · ', $parts );
	}
}
