<?php

namespace Fotogenic_AI;

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

/**
 * Server-owned presentation and navigation model for the shared Studio toolbar.
 *
 * Canonical route query arguments are untrusted navigation hints. This owner
 * allowlists and normalizes them against the same immutable workflow registry,
 * target capability manifest, and WooCommerce availability used by Studio.
 * It does not own drafts, preflight, billable requests, or execution state.
 */
final class Studio_Toolbar_View_Model {

	private function __construct() {}

	/**
	 * Whether a signed navigation payload contains a complete canonical route.
	 */
	public static function has_canonical_route( array $navigation ): bool {
		return isset( $navigation['workflow'], $navigation['sourceType'], $navigation['scope'] );
	}

	/**
	 * Allowlist a complete canonical route without applying runtime availability.
	 *
	 * @return array{workflow: string, sourceType: string, scope: string}|array{}
	 */
	public static function allowlist_route( array $route ): array {
		$workflow   = sanitize_key( (string) ( $route['workflow'] ?? '' ) );
		$source_type = sanitize_key( (string) ( $route['sourceType'] ?? '' ) );
		$scope      = sanitize_key( (string) ( $route['scope'] ?? '' ) );
		$definition = Workflow_Registry::get( $workflow );

		if (
			null === $definition
			|| ! in_array( $source_type, array_keys( $definition->get_sources() ), true )
			|| ! in_array( $scope, [ 'single', 'bulk' ], true )
		) {
			return [];
		}

		return [
			'workflow'   => $workflow,
			'sourceType' => $source_type,
			'scope'      => $scope,
		];
	}

	/**
	 * Resolve one immutable toolbar model for Studio or Settings.
	 *
	 * @param array  $context                Signed canonical Studio route.
	 * @param array  $targets                Studio_Targets_Manifest projection.
	 * @param bool   $woocommerce_available  Actual WooCommerce adapter availability.
	 * @param string $surface                studio|settings.
	 * @return array{
	 *   surface: string,
	 *   available: bool,
	 *   route: array{workflow: string, sourceType: string, scope: string},
	 *   workflowOptions: array<string, array>,
	 *   sourceOptions: array<string, array{id: string, label: string}>,
	 *   settingsUrl: string,
	 *   settingsBaseUrl: string,
	 *   studioUrl: string,
	 *   studioBaseUrl: string
	 * }
	 */
	public static function build( array $context, array $targets, bool $woocommerce_available, string $surface ): array {
		$surface         = 'settings' === $surface ? 'settings' : 'studio';
		$preferred_route = self::route_from_context( $context );
		$route           = self::normalize_route( $preferred_route, $targets, $woocommerce_available );
		$options         = [];

		foreach ( array_keys( Workflow_Registry::all() ) as $workflow_id ) {
			$destination = self::first_route_for_workflow(
				$workflow_id,
				$route['sourceType'],
				$route['scope'],
				$targets,
				$woocommerce_available
			);
			$presentation = self::workflow_presentation( $workflow_id );
			$options[ $workflow_id ] = [
				'id'          => $workflow_id,
				'label'       => $presentation['label'],
				'description' => $presentation['description'],
				'icon'        => $presentation['icon'],
				'enabled'     => null !== $destination,
				'selected'    => $route['workflow'] === $workflow_id,
				'route'       => $destination,
				'url'         => null === $destination ? '' : fotogenic_ai_get_studio_url( $destination ),
			];
		}

		return [
			'surface'        => $surface,
			'available'      => '' !== $route['workflow'],
			'route'          => $route,
			'workflowOptions' => $options,
			'sourceOptions'   => self::source_options( $route['workflow'], $targets, $woocommerce_available ),
			'settingsUrl'     => fotogenic_ai_get_settings_url( $route ),
			'settingsBaseUrl' => fotogenic_ai_get_settings_url(),
			'studioUrl'       => fotogenic_ai_get_studio_url( $route ),
			'studioBaseUrl'   => fotogenic_ai_get_studio_url(),
		];
	}

	/**
	 * Return the currently available sources for the normalized workflow.
	 *
	 * @return array<string, array{id: string, label: string}>
	 */
	private static function source_options( string $workflow_id, array $targets, bool $woocommerce_available ): array {
		$definition = Workflow_Registry::get( $workflow_id );
		if ( null === $definition ) {
			return [];
		}

		$options = [];
		foreach ( $definition->get_sources() as $source_type => $source ) {
			if ( ! self::source_is_available( $workflow_id, $source_type, $source, $targets, $woocommerce_available ) ) {
				continue;
			}

			$options[ $source_type ] = [
				'id'    => $source_type,
				'label' => self::source_label( $source_type ),
			];
		}

		return $options;
	}

	private static function source_label( string $source_type ): string {
		if ( 'product' === $source_type ) {
			return __( 'Product', 'fotogenic-ai' );
		}
		if ( 'post' === $source_type ) {
			return __( 'Post', 'fotogenic-ai' );
		}
		if ( 'page' === $source_type ) {
			return __( 'Page', 'fotogenic-ai' );
		}

		return __( 'Media', 'fotogenic-ai' );
	}

	/**
	 * Normalize a preferred route against current workflow, source, capability,
	 * scope, and WooCommerce availability.
	 *
	 * @return array{workflow: string, sourceType: string, scope: string}
	 */
	public static function normalize_route( array $preferred, array $targets, bool $woocommerce_available ): array {
		$allowlisted = self::allowlist_route( $preferred );
		$workflow_id = (string) ( $allowlisted['workflow'] ?? '' );
		$source_type = (string) ( $allowlisted['sourceType'] ?? '' );
		$scope       = (string) ( $allowlisted['scope'] ?? '' );
		$workflow_ids = array_keys( Workflow_Registry::all() );

		if ( '' !== $workflow_id ) {
			$preferred_route = self::first_route_for_workflow(
				$workflow_id,
				$source_type,
				$scope,
				$targets,
				$woocommerce_available
			);
			if ( null !== $preferred_route ) {
				return $preferred_route;
			}
		}

		foreach ( $workflow_ids as $candidate_workflow ) {
			$candidate = self::first_route_for_workflow(
				$candidate_workflow,
				$source_type,
				$scope,
				$targets,
				$woocommerce_available
			);
			if ( null !== $candidate ) {
				return $candidate;
			}
		}

		// The plugin access capability implies at least one WordPress source, but
		// fail closed if a filtered target manifest removes every valid route.
		return [
			'workflow'   => '',
			'sourceType' => '',
			'scope'      => '',
		];
	}

	/**
	 * Return a complete allowlisted canonical route from signed context.
	 *
	 * @return array{workflow: string, sourceType: string, scope: string}|array{}
	 */
	private static function route_from_context( array $context ): array {
		return self::has_canonical_route( $context ) ? self::allowlist_route( $context ) : [];
	}

	/**
	 * Return the first currently available route within one workflow.
	 *
	 * @return array{workflow: string, sourceType: string, scope: string}|null
	 */
	private static function first_route_for_workflow(
		string $workflow_id,
		string $preferred_source,
		string $preferred_scope,
		array $targets,
		bool $woocommerce_available
	): ?array {
		$definition = Workflow_Registry::get( $workflow_id );
		if ( null === $definition || ! self::workflow_target_is_available( $workflow_id, $targets ) ) {
			return null;
		}

		$sources      = $definition->get_sources();
		$source_order = array_values(
			array_unique(
				array_filter( array_merge( [ $preferred_source ], array_keys( $sources ) ) )
			)
		);
		foreach ( $source_order as $source_type ) {
			$source = $sources[ $source_type ] ?? null;
			if (
				! is_array( $source )
				|| ! self::source_is_available( $workflow_id, $source_type, $source, $targets, $woocommerce_available )
			) {
				continue;
			}

			$scope = self::canonical_scope( $workflow_id, $preferred_scope, (array) ( $source['scopes'] ?? [] ) );
			if ( '' === $scope || ! Workflow_Registry::supports_new_run( $workflow_id, $source_type, $scope ) ) {
				continue;
			}

			return [
				'workflow'   => $workflow_id,
				'sourceType' => $source_type,
				'scope'      => $scope,
			];
		}

		return null;
	}

	private static function canonical_scope( string $workflow_id, string $preferred_scope, array $supported_scopes ): string {
		$preferred_scope = in_array( $preferred_scope, [ 'single', 'bulk' ], true ) ? $preferred_scope : '';
		if ( 'increase_resolution' === $workflow_id ) {
			return in_array( 'single', $supported_scopes, true ) ? 'single' : '';
		}
		if ( in_array( 'bulk', $supported_scopes, true ) ) {
			return 'bulk';
		}
		return in_array( $preferred_scope, $supported_scopes, true ) ? $preferred_scope : (string) ( $supported_scopes[0] ?? '' );
	}

	private static function source_is_available(
		string $workflow_id,
		string $source_type,
		array $source,
		array $targets,
		bool $woocommerce_available
	): bool {
		if ( ! empty( $source['requiresWooCommerce'] ) && ! $woocommerce_available ) {
			return false;
		}
		if ( 'product' === $source_type ) {
			return $woocommerce_available
				&& (
					self::target_is_enabled( $targets, 'product' )
					|| self::target_is_enabled( $targets, 'product_bulk' )
				);
		}
		if ( ! self::target_is_enabled( $targets, $source_type ) ) {
			return false;
		}

		return 'product_images' === $workflow_id || in_array( $source_type, [ 'media' ], true );
	}

	private static function workflow_target_is_available( string $workflow_id, array $targets ): bool {
		if ( 'campaign_set' === $workflow_id ) {
			return self::target_is_enabled( $targets, 'campaign' );
		}
		if ( 'increase_resolution' === $workflow_id ) {
			return self::target_is_enabled( $targets, 'enhance' );
		}
		return true;
	}

	private static function target_is_enabled( array $targets, string $target_id ): bool {
		foreach ( $targets as $target ) {
			if ( is_array( $target ) && $target_id === ( $target['id'] ?? '' ) ) {
				return ! empty( $target['enabled'] );
			}
		}
		return false;
	}

	/**
	 * Return translated, bounded presentation copy for one registered workflow.
	 *
	 * @return array{label: string, description: string, icon: string}
	 */
	private static function workflow_presentation( string $workflow_id ): array {
		if ( 'campaign_set' === $workflow_id ) {
			return [
				'label'       => __( 'Campaign Set', 'fotogenic-ai' ),
				'description' => __( 'Build a coordinated image set with one shared direction.', 'fotogenic-ai' ),
				'icon'        => 'stack-simple',
			];
		}
		if ( 'increase_resolution' === $workflow_id ) {
			return [
				'label'       => __( 'Increase Resolution', 'fotogenic-ai' ),
				'description' => __( 'Upscale an image while preserving the original.', 'fotogenic-ai' ),
				'icon'        => 'arrow-square-up',
			];
		}

		return [
			'label'       => __( 'Generate Images', 'fotogenic-ai' ),
			'description' => __( 'Create new visuals from your selected sources.', 'fotogenic-ai' ),
			'icon'        => 'image-square',
		];
	}
}
