<?php
/**
 * Destination registry. Resolves a type string to its handler class.
 *
 * Third-party extension:
 *   add_filter( 'backreload_register_destinations', function ( array $types ): array {
 *       $types['my_provider'] = \My\Plugin\MyDestination::class;
 *       return $types;
 *   } );
 *
 * @package Backreload\Destinations
 */

namespace Backreload\Destinations;

use Backreload\Plugin;

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

class DestinationManager {

	/** @var array<string,class-string<Destination>> */
	private array $types = [];

	private Plugin $plugin;

	public function __construct( Plugin $plugin ) {
		$this->plugin = $plugin;
	}

	public function boot(): void {
		$built_in = [
			'local'    => LocalDestination::class,
			'ftp'      => FtpDestination::class,
			'sftp'     => SftpDestination::class,
			'google'   => GoogleDestination::class,
			'onedrive' => OnedriveDestination::class,
			'aws'      => AwsDestination::class,
			'wasabi'   => WasabiDestination::class,
			's3'       => S3compatDestination::class,
		];

		$this->types = apply_filters( 'backreload_register_destinations', $built_in );
	}

	/** @return array<string,class-string<Destination>> */
	public function types(): array {
		return $this->types;
	}

	public function has( string $type ): bool {
		return isset( $this->types[ $type ] );
	}

	public function handler( string $type ): Destination {
		if ( ! $this->has( $type ) ) {
			throw new \InvalidArgumentException( esc_html( "Unknown destination type: {$type}" ) );
		}
		$cls = $this->types[ $type ];
		return new $cls();
	}

	/** Metadata about every registered destination for the UI to render the picker. */
	public function catalog(): array {
		$out = [];
		foreach ( $this->types as $type => $cls ) {
			$entry = [
				'type'         => $type,
				'label'        => $cls::label(),
				'schema'       => $cls::config_schema(),
				// Server-side availability info so the picker tile can show a
				// "requires X" warning BEFORE the user fills the form and
				// clicks Save — which is when they'd otherwise hit the
				// "PHP ssh2 extension is required for SFTP" toast (a recurring
				// confusion source per user feedback).
				'availability' => self::availability_for( $type ),
			];
			// Optional `setup_help()` static — destinations like Google Drive
			// and OneDrive that need a multi-step provider setup walkthrough
			// expose it here. React renders a collapsible "Setup help" block
			// inside the config form when this is present.
			if ( method_exists( $cls, 'setup_help' ) ) {
				$entry['setup_help'] = $cls::setup_help();
			}
			$out[] = $entry;
		}
		return $out;
	}

	/**
	 * Whether a given destination type can actually run on this server, plus
	 * a human-readable explanation if it can't. The picker uses this to dim
	 * unavailable tiles and surface a "Install X" hint inline, instead of
	 * letting the user discover the missing extension at save time.
	 *
	 * Returns:
	 *   [
	 *     'available' => bool,   // can the user actually use this destination?
	 *     'reason'    => string, // human-readable, empty when available
	 *     'fix'       => string, // suggested fix when not available
	 *   ]
	 *
	 * @return array{available: bool, reason: string, fix: string}
	 */
	private static function availability_for( string $type ): array {
		switch ( $type ) {
			case 'ftp':
				if ( ! function_exists( 'ftp_connect' ) ) {
					return [
						'available' => false,
						'reason'    => 'The PHP `ftp` extension is not installed on this server.',
						'fix'       => 'Install php-ftp from your OS / hosting control panel, or contact your host to enable it.',
					];
				}
				break;
			case 'sftp':
				if ( ! function_exists( 'ssh2_connect' ) ) {
					return [
						'available' => false,
						'reason'    => 'The PHP `ssh2` extension (PECL) is not installed on this server.',
						'fix'       => 'Install php-ssh2 (e.g. `apt install php-ssh2`, `pecl install ssh2`, or ask your host to enable it). Without it, SFTP destinations cannot connect.',
					];
				}
				break;
			case 's3':
			case 'aws':
			case 'wasabi':
				if ( ! function_exists( 'openssl_encrypt' ) || ! function_exists( 'curl_init' ) ) {
					return [
						'available' => false,
						'reason'    => 'S3-compatible destinations need both the PHP `openssl` and `curl` extensions, and at least one is missing.',
						'fix'       => 'Ask your host to enable php-openssl and php-curl. Both ship by default on almost every host; usually only deliberately stripped-down environments lack them.',
					];
				}
				break;
		}
		return [ 'available' => true, 'reason' => '', 'fix' => '' ];
	}
}
