<?php
/**
 * Diagnostics REST controller.
 *
 * @package Carticy\Conversions\Rest
 */

declare(strict_types=1);

namespace Carticy\Conversions\Rest;

use Carticy\Conversions\Client\ClientTrackingSettings;
use Carticy\Conversions\Diagnostics\GatewayAccuracyReport;
use Carticy\Conversions\Diagnostics\RecentEventsReader;
use Carticy\Conversions\Storage\OrderMetaStore;

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

/**
 * Backs the payment-gateway accuracy report and the recent-events view. Both
 * are COMPUTED from real orders and stored dispatch rows - never asserted - so
 * a healthy status is always earned.
 */
final class DiagnosticsController extends AbstractRestController {

	/**
	 * Max recent orders scanned for the recent-events client baseline.
	 */
	private const RECENT_ORDER_LIMIT = 25;

	/**
	 * Order meta store.
	 *
	 * @var OrderMetaStore
	 */
	private OrderMetaStore $store;

	/**
	 * Accuracy report builder.
	 *
	 * @var GatewayAccuracyReport
	 */
	private GatewayAccuracyReport $accuracy;

	/**
	 * Recent-events transformer.
	 *
	 * @var RecentEventsReader
	 */
	private RecentEventsReader $recent;

	/**
	 * Premium server bridge.
	 *
	 * @var PremiumServerBridge
	 */
	private PremiumServerBridge $server;

	/**
	 * Constructor.
	 *
	 * @param OrderMetaStore        $store Order meta store.
	 * @param GatewayAccuracyReport $accuracy Accuracy report builder.
	 * @param RecentEventsReader    $recent Recent-events transformer.
	 * @param PremiumServerBridge   $server Premium server bridge.
	 */
	public function __construct( OrderMetaStore $store, GatewayAccuracyReport $accuracy, RecentEventsReader $recent, PremiumServerBridge $server ) {
		$this->store    = $store;
		$this->accuracy = $accuracy;
		$this->recent   = $recent;
		$this->server   = $server;
	}

	/**
	 * Declared routes.
	 *
	 * @return array<int, array<string, mixed>>
	 */
	public function routes(): array {
		return array(
			array(
				'methods'  => 'GET',
				'route'    => '/diagnostics/accuracy',
				'callback' => array( $this, 'get_accuracy' ),
				'args'     => array(
					'days' => array(
						'required'          => false,
						'sanitize_callback' => 'absint',
					),
				),
			),
			array(
				'methods'  => 'GET',
				'route'    => '/diagnostics/recent-events',
				'callback' => array( $this, 'get_recent_events' ),
			),
		);
	}

	/**
	 * Payment-gateway accuracy report.
	 *
	 * @param \WP_REST_Request $request REST request.
	 * @return \WP_REST_Response
	 */
	public function get_accuracy( \WP_REST_Request $request ): \WP_REST_Response {
		$days = (int) $request->get_param( 'days' );
		$days = $days > 0 ? $days : 30;

		return $this->ok( $this->accuracy->build( $days ) );
	}

	/**
	 * Recent-events view.
	 *
	 * @return \WP_REST_Response
	 */
	public function get_recent_events(): \WP_REST_Response {
		return $this->ok(
			array(
				'serverSideAvailable' => $this->server->available(),
				'events'              => $this->recent->build(
					$this->store->get_recent_dispatches( 100 ),
					$this->collect_order_events(),
					$this->enabled_client_destinations()
				),
			)
		);
	}

	/**
	 * Enabled client (browser) provider keys, resolved server-side so the
	 * recent-events platforms column never depends on client computation.
	 *
	 * @return array<int, string>
	 */
	private function enabled_client_destinations(): array {
		$client  = ClientTrackingSettings::from_options();
		$enabled = array();
		foreach ( array( 'ga4', 'google_ads', 'meta' ) as $provider ) {
			if ( $client->provider_enabled( $provider ) ) {
				$enabled[] = $provider;
			}
		}

		return $enabled;
	}

	/**
	 * Collect recorded canonical events from the most recent orders.
	 *
	 * @return array<int, array<string, mixed>>
	 */
	private function collect_order_events(): array {
		if ( ! function_exists( 'wc_get_orders' ) ) {
			return array();
		}

		$orders = wc_get_orders(
			array(
				'limit'   => self::RECENT_ORDER_LIMIT,
				'orderby' => 'date',
				'order'   => 'DESC',
				'return'  => 'objects',
			)
		);

		if ( is_object( $orders ) && isset( $orders->orders ) && is_array( $orders->orders ) ) {
			$orders = $orders->orders;
		}

		$events = array();
		foreach ( is_array( $orders ) ? $orders : array() as $order ) {
			if ( ! is_object( $order ) ) {
				continue;
			}

			foreach ( $this->store->get_events( $order ) as $event ) {
				$data     = $event->to_array();
				$events[] = array(
					'orderId'       => $event->order_id(),
					// HPOS-safe edit link (WC_Order::get_edit_order_url routes to
					// wc-orders or post.php as appropriate) so the row can deep-link
					// to the order instead of leaving the merchant to hunt for it.
					'orderUrl'      => method_exists( $order, 'get_edit_order_url' ) ? (string) $order->get_edit_order_url() : '',
					'eventType'     => $event->event_type(),
					'eventId'       => $event->event_id(),
					'occurredAt'    => (string) ( $data['occurred_at'] ?? '' ),
					'clientTracked' => true,
				);
			}
		}

		return $events;
	}
}
