<?php
/**
 * Normalized, competitor-agnostic result of reading one competitor's config.
 *
 * @package StoreSheet
 */

declare( strict_types=1 );

namespace StoreSheet\Importer;

defined( 'ABSPATH' ) || exit;

/**
 * ImportPlan represents a normalized import configuration from a competitor source.
 */
final class ImportPlan {

	/** @var string */
	public $source_id;

	/** @var string */
	public $source_label;

	/** @var array<string,string>|null client id/secret if stored locally; secret never sent to the browser. */
	public $credentials;

	/** @var array{id:string,url:string}|null */
	public $spreadsheet;

	/** @var array<string,mixed> Subset of storesheet_settings keys. */
	public $settings;

	/** @var array<int,array{column:string,target:string}> */
	public $field_mappings;

	/** @var string[] */
	public $warnings;

	/**
	 * Constructor.
	 *
	 * @param string                                        $source_id
	 * @param string                                        $source_label
	 * @param array<string,string>|null                     $credentials
	 * @param array{id:string,url:string}|null              $spreadsheet
	 * @param array<string,mixed>                           $settings
	 * @param array<int,array{column:string,target:string}> $field_mappings
	 * @param string[]                                      $warnings
	 */
	public function __construct(
		string $source_id,
		string $source_label,
		?array $credentials,
		?array $spreadsheet,
		array $settings,
		array $field_mappings,
		array $warnings
	) {
		$this->source_id      = $source_id;
		$this->source_label   = $source_label;
		$this->credentials    = $credentials;
		$this->spreadsheet    = $spreadsheet;
		$this->settings       = $settings;
		$this->field_mappings = $field_mappings;
		$this->warnings       = $warnings;
	}

	/**
	 * Transport shape. The client secret is replaced by a presence boolean so it
	 * never reaches the browser.
	 *
	 * @return array<string,mixed>
	 */
	public function to_array(): array {
		$credentials = null;
		if ( null !== $this->credentials ) {
			$credentials = array(
				'oauth_client_id'             => (string) ( $this->credentials['oauth_client_id'] ?? '' ),
				'oauth_client_secret_present' => ! empty( $this->credentials['oauth_client_secret'] ),
			);
		}

		return array(
			'source_id'      => $this->source_id,
			'source_label'   => $this->source_label,
			'credentials'    => $credentials,
			'spreadsheet'    => $this->spreadsheet,
			'settings'       => $this->settings,
			'field_mappings' => $this->field_mappings,
			'warnings'       => $this->warnings,
		);
	}

	/**
	 * Rebuild from a stored/transport array. Secrets are not present in transport
	 * arrays, so credentials come back without a secret (callers that need the
	 * secret re-read the adapter server-side).
	 *
	 * @param array<string,mixed> $a
	 * @return self
	 */
	public static function from_array( array $a ): self {
		return new self(
			(string) ( $a['source_id'] ?? '' ),
			(string) ( $a['source_label'] ?? '' ),
			isset( $a['credentials'] ) && is_array( $a['credentials'] ) ? $a['credentials'] : null,
			isset( $a['spreadsheet'] ) && is_array( $a['spreadsheet'] )
				? array(
					'id'  => (string) ( $a['spreadsheet']['id'] ?? '' ),
					'url' => (string) ( $a['spreadsheet']['url'] ?? '' ),
				)
				: null,
			is_array( $a['settings'] ?? null ) ? $a['settings'] : array(),
			is_array( $a['field_mappings'] ?? null ) ? $a['field_mappings'] : array(),
			is_array( $a['warnings'] ?? null ) ? $a['warnings'] : array()
		);
	}
}
