<?php

namespace WcElectronInvoice\Providers;

abstract class OrdersProviderAbstract {

	const ORDERS_DEFAULT_LIST_STATUSES = ['processing', 'completed', 'refunded'];

	/**
	 * Get orders
	 *
	 * @param array $args
	 *
	 * @return array
	 */
	public abstract function getOrders( $args = array());

	/**
	 * Return lightweight normalized document summaries for the admin XML list.
	 *
	 * The summary shape is intentionally array-based because the list pipeline
	 * persists the merged index for later bulk resolution.
	 *
	 * @param array $args
	 *
	 * @return array<int, array<string, mixed>>
	 */
	public abstract function getOrderSummaries( $args = array() );

	/**
	 * Get order
	 * @param $orderId
	 *
	 * @return mixed
	 */
	public abstract function getOrder( $orderId );

	/**
	 * Enqueue the provider
	 *
	 * @return void
	 */
	public function enqueue() {
		OrderQuery::instance()->register_provider( $this );
	}

	/**
	 * Maps WooCommerce's query args to the provider's query args
	 * @param $args
	 *
	 * @return mixed
	 */
	abstract function mapArgs( $args );

	/**
	 * Get the provider name (slug, like woocommerce, pmpro, etc.)
	 * @return string
	 */
	public abstract function name();

	/**
	 * Get the provider label (like WooCommerce, PMPro, etc.)
	 * @return string
	 */
	public abstract function get_label();

	/**
	 * Build a stable key for a provider document summary.
	 *
	 * @param array<string, mixed> $summary
	 *
	 * @return string
	 */
	protected function buildSummaryDocumentKey( array $summary ) {
		return implode( ':', array(
			isset( $summary['provider'] ) ? (string) $summary['provider'] : $this->name(),
			isset( $summary['document_type'] ) ? (string) $summary['document_type'] : 'shop_order',
			isset( $summary['id'] ) ? (string) $summary['id'] : '0',
			isset( $summary['parent_id'] ) ? (string) $summary['parent_id'] : '0',
		) );
	}

	/**
	 * Normalize a provider document into the XML-list summary contract.
	 *
	 * @param OrderAbstract         $order
	 * @param array<string, mixed>  $extra
	 *
	 * @return array<string, mixed>
	 */
	protected function buildOrderSummary( OrderAbstract $order, array $extra = array() ) {
		$dateCreated = method_exists( $order, 'get_date_created' ) ? $this->normalizeSummaryDateValue( $order->get_date_created() ) : null;
		$dateModified = method_exists( $order, 'get_date_modified' ) ? $this->normalizeSummaryDateValue( $order->get_date_modified() ) : null;
		$dateCompleted = method_exists( $order, 'get_date_completed' ) ? $this->normalizeSummaryDateValue( $order->get_date_completed() ) : null;

		$summary = array(
			'id'             => (int) $order->get_id(),
			'provider'       => $order->get_provider(),
			'provider_label' => $order->get_provider_label(),
			'document_type'  => (string) $order->get_type(),
			'order_type'     => (string) $order->get_type(),
			'parent_id'      => (int) $order->get_parent_id(),
			'status'         => (string) $order->get_status(),
			'date_created'   => $dateCreated,
			'date_modified'  => $dateModified,
			'date_completed' => $dateCompleted,
			'invoice_number' => (string) $order->get_order_number_invoice(),
			'invoice_sent'   => $order->get_invoice_sent(),
			'choice_type'    => (string) $order->get_billing_choice_type(),
			'invoice_type'   => (string) $order->get_invoice_type(),
			'total'          => (float) $order->get_total(),
			'total_tax'      => method_exists( $order, 'get_total_tax' ) ? (float) $order->get_total_tax() : 0.0,
			'total_refunded' => (float) $order->get_total_refunded(),
			'sort_date'      => $dateCompleted ?: $dateCreated ?: $dateModified ?: 0,
		);

		$summary = array_merge( $summary, $extra );
		if ( ! isset( $summary['document_key'] ) || '' === (string) $summary['document_key'] ) {
			$summary['document_key'] = $this->buildSummaryDocumentKey( $summary );
		}

		return $summary;
	}

	/**
	 * Normalize supported date values into Unix timestamps for cross-provider sort/filter.
	 *
	 * @param mixed $value
	 *
	 * @return int|null
	 */
	protected function normalizeSummaryDateValue( $value ) {
		if ( $value instanceof \WC_DateTime || $value instanceof \DateTimeInterface ) {
			return $value->getTimestamp();
		}

		if ( is_numeric( $value ) ) {
			return (int) $value;
		}

		if ( is_string( $value ) && '' !== trim( $value ) ) {
			$timestamp = strtotime( $value );
			if ( false !== $timestamp ) {
				return (int) $timestamp;
			}
		}

		return null;
	}

}
