<?php
/**
 * Lazy provider registry.
 *
 * @package EmailSmtp
 */

namespace EmailSmtp\Includes;

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

final class ProviderRegistry {

	/** @var array<string, class-string<ProviderInterface>> */
	private static array $class_map = [];

	/** @var array<string, ProviderInterface> */
	private static array $instances = [];

	private static bool $bootstrapped = false;

	public static function bootstrap(): void {
		if ( self::$bootstrapped ) {
			return;
		}
		self::$bootstrapped = true;

		// Picker order: Custom SMTP first, then by popularity, PHP Mail last.
		self::register( 'smtp', \EmailSmtp\Providers\Smtp\Provider::class );
		self::register( 'sendgrid', \EmailSmtp\Providers\Sendgrid\Provider::class );
		self::register( 'amazon-ses', \EmailSmtp\Providers\AmazonSes\Provider::class );
		self::register( 'mailgun', \EmailSmtp\Providers\Mailgun\Provider::class );
		self::register( 'brevo', \EmailSmtp\Providers\Brevo\Provider::class );
		self::register( 'google', \EmailSmtp\Providers\Google\Provider::class );
		self::register( 'microsoft', \EmailSmtp\Providers\Microsoft\Provider::class );
		self::register( 'postmark', \EmailSmtp\Providers\Postmark\Provider::class );
		self::register( 'mailjet', \EmailSmtp\Providers\Mailjet\Provider::class );
		self::register( 'mailersend', \EmailSmtp\Providers\Mailersend\Provider::class );
		self::register( 'smtp2go', \EmailSmtp\Providers\Smtp2go\Provider::class );
		self::register( 'resend', \EmailSmtp\Providers\Resend\Provider::class );
		self::register( 'mandrill', \EmailSmtp\Providers\Mandrill\Provider::class );
		self::register( 'sparkpost', \EmailSmtp\Providers\Sparkpost\Provider::class );
		self::register( 'elastic-email', \EmailSmtp\Providers\ElasticEmail\Provider::class );
		self::register( 'sendlayer', \EmailSmtp\Providers\Sendlayer\Provider::class );
		self::register( 'smtpcom', \EmailSmtp\Providers\Smtpcom\Provider::class );
		self::register( 'netcore', \EmailSmtp\Providers\Netcore\Provider::class );
		self::register( 'turbo-smtp', \EmailSmtp\Providers\TurboSmtp\Provider::class );
		self::register( 'maileroo', \EmailSmtp\Providers\Maileroo\Provider::class );
		self::register( 'emailit', \EmailSmtp\Providers\Emailit\Provider::class );
		self::register( 'mail-baby', \EmailSmtp\Providers\MailBaby\Provider::class );
		self::register( 'wordpress', \EmailSmtp\Providers\Wordpress\Provider::class );

		/**
		 * Register additional email delivery providers.
		 *
		 * @param ProviderRegistry $registry Registry helper (static API; passed for filter ergonomics).
		 */
		if ( function_exists( 'do_action' ) ) {
			do_action( 'wp_powersuite_email_delivery_provider_registry', new self() );
		}
	}

	/**
	 * Register a provider class for lazy loading. The class file is not loaded until get().
	 *
	 * @param class-string<ProviderInterface> $class
	 */
	public static function register( string $id, string $class ): void {
		$id = sanitize_key( $id );
		if ( $id === '' || $class === '' ) {
			return;
		}
		self::$class_map[ $id ] = $class;
	}

	public function add( string $id, string $class ): void {
		self::register( $id, $class );
	}

	public static function get( string $id ): ?ProviderInterface {
		self::bootstrap();
		$id = sanitize_key( $id );
		if ( $id === '' || ! isset( self::$class_map[ $id ] ) ) {
			return null;
		}

		if ( ! isset( self::$instances[ $id ] ) ) {
			$class = self::$class_map[ $id ];
			self::maybe_load_class_file( $id, $class );
			if ( ! class_exists( $class ) || ! is_subclass_of( $class, ProviderInterface::class ) ) {
				return null;
			}
			self::$instances[ $id ] = new $class();
		}

		return self::$instances[ $id ];
	}

	/**
	 * @return list<array{id:string,name:string,description:string,transport_label:string,recommended_use:string}>
	 */
	public static function cards(): array {
		self::bootstrap();
		$catalog = self::built_in_catalog();
		$cards   = [];

		foreach ( array_keys( self::$class_map ) as $id ) {
			if ( isset( $catalog[ $id ] ) ) {
				$row     = $catalog[ $id ];
				$cards[] = [
					'id'               => $id,
					'name'             => __( $row['name'], 'wp-powersuite' ), // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText
					'description'      => __( $row['description'], 'wp-powersuite' ), // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText
					'transport_label'  => self::transport_label_for( $id ),
					'recommended_use'  => $row['recommended_use'] !== ''
						? __( $row['recommended_use'], 'wp-powersuite' ) // phpcs:ignore WordPress.WP.I18n.NonSingularStringLiteralText
						: '',
				];
				continue;
			}

			// Extension providers: load only when not in the built-in catalog.
			$provider = self::get( $id );
			if ( ! $provider instanceof ProviderInterface ) {
				continue;
			}
			$cards[] = [
				'id'              => $provider->get_id(),
				'name'            => $provider->get_name(),
				'description'     => $provider->get_description(),
				'transport_label' => $provider->get_transport_label(),
				'recommended_use' => $provider->get_recommended_use(),
			];
		}

		/**
		 * Filter lightweight provider cards shown in Email Delivery admin pickers.
		 *
		 * @param list<array{id:string,name:string,description:string,transport_label:string,recommended_use:string}> $cards
		 */
		return apply_filters( 'wp_powersuite_email_delivery_provider_cards', $cards );
	}

	/**
	 * @return list<string>
	 */
	public static function ids(): array {
		self::bootstrap();
		return array_keys( self::$class_map );
	}

	public static function transport_label_for( string $id ): string {
		$id = sanitize_key( $id );
		if ( $id === 'wordpress' ) {
			return __( 'PHP Mail', 'wp-powersuite' );
		}
		if ( $id === 'smtp' ) {
			return __( 'SMTP', 'wp-powersuite' );
		}
		if ( in_array( $id, [ 'google', 'microsoft' ], true ) ) {
			return __( 'OAuth', 'wp-powersuite' );
		}
		return __( 'API', 'wp-powersuite' );
	}

	/**
	 * Built-in picker copy (mirrors Provider::get_* strings without loading classes).
	 *
	 * @return array<string, array{name:string, description:string, recommended_use:string}>
	 */
	private static function built_in_catalog(): array {
		return [
			'smtp'          => [
				'name'            => 'Custom SMTP',
				'description'     => 'Send through any SMTP server, including hosting mail and provider SMTP relays (SendGrid, Mailgun, and others).',
				'recommended_use' => 'Use when you have SMTP credentials. Prefer the named API mailer when the provider is listed.',
			],
			'sendgrid'      => [
				'name'            => 'SendGrid',
				'description'     => 'Send via the Twilio SendGrid Web API v3 with an API key.',
				'recommended_use' => 'High-volume transactional email with strong analytics.',
			],
			'amazon-ses'    => [
				'name'            => 'Amazon SES',
				'description'     => 'Send transactional email through Amazon SES with IAM access keys.',
				'recommended_use' => 'High-volume transactional mail on AWS. Verify your domain, then request production access if you are still in the sandbox.',
			],
			'mailgun'       => [
				'name'            => 'Mailgun',
				'description'     => 'Send through Mailgun using a sending domain and private API key.',
				'recommended_use' => 'Transactional and bulk mail with domain verification.',
			],
			'brevo'         => [
				'name'            => 'Brevo',
				'description'     => 'Send transactional email through the Brevo API v3.',
				'recommended_use' => 'Transactional mail with marketing platform overlap.',
			],
			'google'        => [
				'name'            => 'Gmail / Google Workspace',
				'description'     => 'Send through the Gmail API with OAuth 2.0 (gmail.send). No mailbox password stored.',
				'recommended_use' => 'Low-to-moderate volume from a Google account or Workspace mailbox. Prefer a dedicated ESP for high volume.',
			],
			'microsoft'     => [
				'name'            => 'Microsoft 365 / Outlook',
				'description'     => 'Send through Microsoft Graph with delegated OAuth (Mail.Send). No mailbox password stored.',
				'recommended_use' => 'Microsoft 365 or Outlook.com mailboxes. Prefer a dedicated ESP for high-volume transactional mail.',
			],
			'postmark'      => [
				'name'            => 'Postmark',
				'description'     => 'Send transactional email through the Postmark Email API.',
				'recommended_use' => 'Transactional email with message streams.',
			],
			'mailjet'       => [
				'name'            => 'Mailjet',
				'description'     => 'Send transactional email through the Mailjet v3.1 Send API.',
				'recommended_use' => '',
			],
			'mailersend'    => [
				'name'            => 'MailerSend',
				'description'     => 'Send transactional email through the MailerSend Email API v1.',
				'recommended_use' => 'Transactional email with verified sending domains.',
			],
			'smtp2go'       => [
				'name'            => 'SMTP2GO',
				'description'     => 'Send email through the SMTP2GO REST API v3.',
				'recommended_use' => '',
			],
			'resend'        => [
				'name'            => 'Resend',
				'description'     => 'Send transactional email through the Resend REST API.',
				'recommended_use' => 'Developer-friendly transactional delivery.',
			],
			'mandrill'      => [
				'name'            => 'Mandrill',
				'description'     => 'Send transactional email through Mandrill (Mailchimp Transactional).',
				'recommended_use' => '',
			],
			'sparkpost'     => [
				'name'            => 'SparkPost',
				'description'     => 'Send transactional email through Bird Email (SparkPost) API.',
				'recommended_use' => '',
			],
			'elastic-email' => [
				'name'            => 'Elastic Email',
				'description'     => 'Send transactional email through the Elastic Email REST API v4.',
				'recommended_use' => '',
			],
			'sendlayer'     => [
				'name'            => 'SendLayer',
				'description'     => 'Send transactional email through the SendLayer REST API.',
				'recommended_use' => '',
			],
			'smtpcom'       => [
				'name'            => 'SMTP.com',
				'description'     => 'Send email through the SMTP.com Channel API (v4).',
				'recommended_use' => '',
			],
			'netcore'       => [
				'name'            => 'Netcore',
				'description'     => 'Send email through the Netcore Email API (formerly Pepipost).',
				'recommended_use' => '',
			],
			'turbo-smtp'    => [
				'name'            => 'TurboSMTP',
				'description'     => 'Send email through the TurboSMTP mail API using consumer key credentials.',
				'recommended_use' => '',
			],
			'maileroo'      => [
				'name'            => 'Maileroo',
				'description'     => 'Send transactional email through the Maileroo Email API.',
				'recommended_use' => '',
			],
			'emailit'       => [
				'name'            => 'Emailit',
				'description'     => 'Send transactional email through the Emailit API.',
				'recommended_use' => '',
			],
			'mail-baby'     => [
				'name'            => 'Mail.baby',
				'description'     => 'Send transactional email through the Mail.baby REST API.',
				'recommended_use' => '',
			],
			'wordpress'     => [
				'name'            => 'PHP Mail',
				'description'     => 'Send through PHP mail() / the server mailer without SMTP or an external API.',
				'recommended_use' => 'Local or staging sites where deliverability is not critical.',
			],
		];
	}

	/**
	 * @param class-string<ProviderInterface> $class
	 */
	private static function maybe_load_class_file( string $id, string $class ): void {
		if ( class_exists( $class, false ) ) {
			return;
		}

		$base = dirname( __DIR__ ) . '/providers/' . $id . '/Provider.php';
		if ( is_readable( $base ) ) {
			require_once $base;
		}
	}
}
