<?php
/**
 * Public field provider contract.
 *
 * @package ScheduledChanges
 */

namespace ScheduledChanges\Provider;

use ScheduledChanges\Field\FieldCollection;
use ScheduledChanges\Field\FieldDefinition;

/**
 * Public extension contract implemented by core and third-party field owners.
 * The interface is retained as the provider polymorphism boundary.
 */
interface FieldProvider {
	public function id(): string;

	public function version(): string;

	public function category(): string;

	/**
	 * @throws \RuntimeException When provider state required to evaluate support is unavailable.
	 */
	public function supports( ObjectContext $context ): bool;

	/**
	 * @throws \RuntimeException When field discovery cannot be completed for the target context.
	 */
	public function discover( ObjectContext $context ): FieldCollection;

	/**
	 * @return mixed
	 * @throws \RuntimeException When the provider-owned value cannot be read.
	 */
	public function read( ObjectContext $context, FieldDefinition $field );

	/**
	 * @param mixed $value
	 * @return mixed
	 * @throws \InvalidArgumentException When the value cannot be normalized to the field type.
	 */
	public function normalize( FieldDefinition $field, $value );

	/**
	 * @param mixed $value
	 * @throws \RuntimeException When provider validation depends on unavailable runtime state.
	 */
	public function validate(
		ObjectContext $context,
		FieldDefinition $field,
		$value
	): ValidationResult;

	/**
	 * @param mixed $value
	 * @throws \RuntimeException When an unexpected infrastructure failure prevents an OperationResult from being returned.
	 */
	public function write(
		ObjectContext $context,
		FieldDefinition $field,
		$value,
		ExecutionContext $execution
	): OperationResult;

	/**
	 * @throws \RuntimeException When provider-owned state cannot be snapshotted.
	 */
	public function snapshot( ObjectContext $context ): ProviderSnapshot;

	/**
	 * @throws \RuntimeException When provider snapshots cannot be compared.
	 */
	public function diff( ProviderSnapshot $before, ProviderSnapshot $after ): ChangeCollection;

	/**
	 * @throws \RuntimeException When an unexpected infrastructure failure prevents an OperationResult from being returned.
	 */
	public function rollback(
		ObjectContext $context,
		ProviderSnapshot $snapshot,
		RollbackContext $rollback
	): OperationResult;
}
