<?php
/**
 * Existing-tag detection REST controller.
 *
 * @package Carticy\Conversions\Rest
 */

declare(strict_types=1);

namespace Carticy\Conversions\Rest;

use Carticy\Conversions\Diagnostics\DetectionResolutions;
use Carticy\Conversions\Diagnostics\ExistingTagScanner;

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

/**
 * Backs the "we found a Pixel" banner and the attach/replace/keep-both screen.
 * Without this contract those screens have no data; it returns what was found
 * and the recommended safe action. The merchant's per-tag resolution persists
 * via POST /detection/resolution so an acknowledged duplicate stops re-raising
 * the warning.
 */
final class DetectionController extends AbstractRestController {

	/**
	 * Tag scanner.
	 *
	 * @var ExistingTagScanner
	 */
	private ExistingTagScanner $scanner;

	/**
	 * Persisted merchant resolutions.
	 *
	 * @var DetectionResolutions
	 */
	private DetectionResolutions $resolutions;

	/**
	 * Constructor.
	 *
	 * @param ExistingTagScanner        $scanner Tag scanner.
	 * @param DetectionResolutions|null $resolutions Persisted merchant resolutions.
	 */
	public function __construct( ExistingTagScanner $scanner, ?DetectionResolutions $resolutions = null ) {
		$this->scanner     = $scanner;
		$this->resolutions = $resolutions ?? new DetectionResolutions();
	}

	/**
	 * Declared routes.
	 *
	 * @return array<int, array<string, mixed>>
	 */
	public function routes(): array {
		return array(
			array(
				'methods'  => 'GET',
				'route'    => '/detection',
				'callback' => array( $this, 'get_detection' ),
			),
			array(
				'methods'  => 'POST',
				'route'    => '/detection/resolution',
				'callback' => array( $this, 'save_resolution' ),
			),
		);
	}

	/**
	 * Scan for foreign tags, merging an optional browser probe.
	 *
	 * @param \WP_REST_Request $request REST request.
	 * @return \WP_REST_Response
	 */
	public function get_detection( \WP_REST_Request $request ): \WP_REST_Response {
		$probe  = $request->get_param( 'probe' );
		$result = $this->scanner->scan( is_array( $probe ) ? $probe : array() );

		// Decorate every found tag with the merchant's stored resolution so the
		// UI can render an already-answered detection without re-asking.
		foreach ( $result['found'] as $index => $item ) {
			$result['found'][ $index ]['resolution'] = $this->resolutions->action_for(
				(string) ( $item['type'] ?? '' ),
				(string) ( $item['id'] ?? '' )
			);
		}
		$result['resolutions'] = $this->resolutions->all();

		return $this->ok( $result );
	}

	/**
	 * Persist the merchant's attach/replace/keep-both decisions.
	 *
	 * @param \WP_REST_Request $request REST request.
	 * @return \WP_REST_Response|\WP_Error
	 */
	public function save_resolution( \WP_REST_Request $request ) {
		$body = $this->body( $request );
		$rows = isset( $body['resolutions'] ) && is_array( $body['resolutions'] ) ? $body['resolutions'] : array();
		if ( array() === $rows ) {
			return $this->fail( 'carticy_invalid_body', __( 'At least one resolution is required.', 'carticy-conversions-for-woocommerce' ), 400 );
		}

		return $this->ok( array( 'resolutions' => $this->resolutions->apply( $rows ) ) );
	}
}
