<?php
/**
 * Create Fundraiser Form Block
 *
 * Context-aware multi-step form for creating fundraisers.
 *
 * @package AmbassadorHub\Fundraisers\Blocks\CreateFundraiserForm
 */

namespace AmbassadorHub\Fundraisers\Blocks\CreateFundraiserForm;

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

use AmbassadorHub\Accounts\AccountFields;
use AmbassadorHub\Accounts\Admin\Settings\SettingsManager;
use AmbassadorHub\Fundraisers\FundraisersModule;
use AmbassadorHub\Fundraisers\Admin\Settings\SettingsManager as FundraiserSettingsManager;

use function apply_filters;

/**
 * Block registration and server-side rendering.
 */
final class Block {

	/**
	 * Whether the one-time global JS data has been added to the page.
	 *
	 * Prevents duplicate window.ambhUserId / window.ambhApiBase inline scripts
	 * when multiple instances of the block appear on the same page.
	 */
	private static bool $global_data_printed = false;

	/**
	 * Initialize the block.
	 *
	 * @return void
	 */
	public static function init(): void {
		add_action( 'init', array( self::class, 'register_block' ) );
	}

	/**
	 * Register block type, scripts, and styles.
	 *
	 * @return void
	 */
	public static function register_block(): void {
		$block_dir = AMBASSADOR_HUB_PATH . 'src/Fundraisers/Blocks/CreateFundraiserForm/';
		$block_url = AMBASSADOR_HUB_URL . 'src/Fundraisers/Blocks/CreateFundraiserForm/';

		// Editor script.
		$editor_handle = 'ambh-create-fundraiser-form-editor';
		$editor_file   = $block_dir . 'index.js';
		if ( file_exists( $editor_file ) ) {
			wp_register_script(
				$editor_handle,
				$block_url . 'index.js',
				array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-block-editor' ),
				(string) filemtime( $editor_file ),
				true
			);
		}

		// Frontend script.
		$frontend_handle = 'ambh-create-fundraiser-form-frontend';
		$frontend_file   = $block_dir . 'frontend.js';
		if ( file_exists( $frontend_file ) ) {
			wp_register_script(
				$frontend_handle,
				$block_url . 'frontend.js',
				array( 'wp-hooks' ),
				(string) filemtime( $frontend_file ),
				true
			);
		}

		// Styles.
		$style_file = $block_dir . 'style.css';
		wp_register_style(
			'ambh-create-fundraiser-form',
			$block_url . 'style.css',
			array(),
			file_exists( $style_file ) ? (string) filemtime( $style_file ) : AMBASSADOR_HUB_VERSION
		);

		$block_args = array(
			'style'           => 'ambh-create-fundraiser-form',
			'render_callback' => array( self::class, 'render_block' ),
		);

		if ( file_exists( $editor_file ) ) {
			$block_args['editor_script'] = $editor_handle;
		}

		register_block_type( $block_dir, $block_args );
	}

	/**
	 * Server-side render callback.
	 *
	 * @param array $attributes Block attributes.
	 *
	 * @return string Rendered HTML.
	 */
	public static function render_block( array $attributes = array() ): string {
		// Editor placeholder — shown in the block editor canvas.
		if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
			return '<div class="ambh-block-preview ambh-block-preview--create-fundraiser">'
				. esc_html__( 'Create Fundraiser Form (renders on the frontend)', 'ambassadorhub' )
				. '</div>';
		}

		// Require the visitor to be authenticated — show login/register form.
		if ( ! is_user_logged_in() ) {
			wp_enqueue_style( 'ambh-create-fundraiser-form' );
			return self::render_auth_prompt();
		}

		// ── Edit mode ─────────────────────────────────────────────────────────
		// When the page is loaded with ?edit_fundraiser_id=X the block switches
		// to edit mode: campaign/type steps are skipped, existing values are
		// pre-populated, and the form submits a PATCH instead of POST.
		$edit_fundraiser_id = isset( $_GET['edit_fundraiser_id'] ) // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only; destructive action uses the REST nonce.
			? absint( $_GET['edit_fundraiser_id'] )                // phpcs:ignore WordPress.Security.NonceVerification.Recommended
			: 0;

		$edit_data = array();

		if ( $edit_fundraiser_id > 0 ) {
			$edit_post = get_post( $edit_fundraiser_id );

			if ( ! $edit_post || FundraisersModule::POST_TYPE !== $edit_post->post_type ) {
				return '<p class="ambh-cff-error">'
					. esc_html__( 'Fundraiser not found.', 'ambassadorhub' )
					. '</p>';
			}

			if ( get_current_user_id() !== (int) $edit_post->post_author ) {
				return '<p class="ambh-cff-error">'
					. esc_html__( 'You do not have permission to edit this fundraiser.', 'ambassadorhub' )
					. '</p>';
			}

			$edit_thumb_id  = (int) get_post_thumbnail_id( $edit_fundraiser_id );
			$edit_thumb_url = $edit_thumb_id
				? (string) wp_get_attachment_image_url( $edit_thumb_id, 'medium' )
				: '';

			$edit_data = array(
				'id'            => $edit_fundraiser_id,
				'title'         => $edit_post->post_title,
				'content'       => $edit_post->post_content,
				'target_amount' => (string) get_post_meta( $edit_fundraiser_id, '_ambh_target_amount', true ),
				'thumbnail_url' => $edit_thumb_url,
				'permalink'     => (string) get_permalink( $edit_post ),
			);
		}
		// ──────────────────────────────────────────────────────────────────────

		$context              = ContextResolver::resolve( $attributes );
		$context['edit_data'] = $edit_data;

		// Merge the block's auto-generated wrapper attributes (alignment, layout,
		// spacing, block class) with our own class so the theme's content-width
		// constraints and Global Styles apply to the form.
		$context['wrapper_attrs'] = get_block_wrapper_attributes(
			array( 'class' => 'ambh-create-fundraiser-form' )
		);

		self::enqueue_frontend();

		ob_start();
		require __DIR__ . '/templates/wrapper.php';
		return (string) ob_get_clean();
	}

	/**
	 * Enqueue the frontend script and add one-time page-level globals.
	 *
	 * The inline globals (user ID, REST base) are added once regardless of how
	 * many Create Fundraiser Form blocks appear on the same page.
	 *
	 * @param array $context Resolved context from ContextResolver::resolve().
	 *
	 * @return void
	 */
	/**
	 * Render an inline login + signup prompt for unauthenticated visitors.
	 *
	 * If a dedicated login page is configured in the plugin settings, redirects
	 * there with a redirect_to param so the user lands back on this page after
	 * authenticating. Otherwise renders login and signup forms inline using the
	 * same action handlers as the Ambassador Signup block.
	 *
	 * @return string HTML, or triggers a redirect + exit.
	 */
	private static function render_auth_prompt(): string {
		// Prefer the configured login/signup page (avoids duplicating forms).
		if ( SettingsManager::is_login_page_configured() ) {
			$current_url = home_url( add_query_arg( array() ) );
			$login_url   = add_query_arg( 'redirect_to', rawurlencode( $current_url ), SettingsManager::get_login_page_url() );
			wp_safe_redirect( $login_url );
			exit;
		}

		$current_url   = home_url( add_query_arg( array() ) );
		$action_signup = admin_url( 'admin-post.php?action=ambh_ambassador_signup' );
		$action_login  = admin_url( 'admin-post.php?action=ambh_ambassador_login' );

		// phpcs:disable WordPress.Security.NonceVerification.Recommended -- read-only display; actual form actions use nonces.
		$error_code = isset( $_GET['ambh_error'] ) ? sanitize_key( $_GET['ambh_error'] ) : '';
		$error_form = isset( $_GET['ambh_form'] ) ? sanitize_key( $_GET['ambh_form'] ) : '';
		// phpcs:enable

		ob_start();
		?>
		<div class="ambh-cff-auth">
			<p class="ambh-cff-auth__intro"><?php esc_html_e( 'You need an account to create a fundraiser.', 'ambassadorhub' ); ?></p>
			<div class="ambh-cff-auth__columns">

				<div class="ambh-cff-auth__box">
					<h3><?php esc_html_e( 'Register', 'ambassadorhub' ); ?></h3>
					<?php if ( $error_code && 'signup' === $error_form ) : ?>
						<div class="ambh-cff-auth__error"><?php echo esc_html( self::auth_error_message( $error_code ) ); ?></div>
					<?php endif; ?>
					<form method="post" action="<?php echo esc_url( $action_signup ); ?>">
						<?php wp_nonce_field( 'ambh_ambassador_signup', '_ambh_nonce' ); ?>
						<input type="hidden" name="redirect_to" value="<?php echo esc_attr( $current_url ); ?>" />
						<p>
							<label for="ambh-cff-first-name"><?php esc_html_e( 'First name', 'ambassadorhub' ); ?></label>
							<input type="text" name="first_name" id="ambh-cff-first-name" required />
						</p>
						<p>
							<label for="ambh-cff-last-name"><?php esc_html_e( 'Last name', 'ambassadorhub' ); ?></label>
							<input type="text" name="last_name" id="ambh-cff-last-name" required />
						</p>
						<?php AccountFields::render_signup_fields(); ?>
						<p>
							<label for="ambh-cff-signup-email"><?php esc_html_e( 'Email', 'ambassadorhub' ); ?></label>
							<input type="email" name="email" id="ambh-cff-signup-email" required />
						</p>
						<p>
							<label for="ambh-cff-signup-password"><?php esc_html_e( 'Password', 'ambassadorhub' ); ?></label>
							<input type="password" name="password" id="ambh-cff-signup-password" required autocomplete="new-password" />
						</p>
						<?php do_action( 'ambh_render_registration_form_fields' ); ?>
						<p>
							<button type="submit" class="ambh-cff-auth__button ambh-cff-auth__button--primary"><?php esc_html_e( 'Sign up', 'ambassadorhub' ); ?></button>
						</p>
					</form>
				</div>

				<div class="ambh-cff-auth__box">
					<h3><?php esc_html_e( 'Login', 'ambassadorhub' ); ?></h3>
					<?php if ( $error_code && 'login' === $error_form ) : ?>
						<div class="ambh-cff-auth__error"><?php echo esc_html( self::auth_error_message( $error_code ) ); ?></div>
					<?php endif; ?>
					<form method="post" action="<?php echo esc_url( $action_login ); ?>">
						<?php wp_nonce_field( 'ambh_ambassador_login', '_ambh_nonce' ); ?>
						<input type="hidden" name="redirect_to" value="<?php echo esc_attr( $current_url ); ?>" />
						<p>
							<label for="ambh-cff-login-email"><?php esc_html_e( 'Email', 'ambassadorhub' ); ?></label>
							<input type="email" name="email" id="ambh-cff-login-email" required />
						</p>
						<p>
							<label for="ambh-cff-login-password"><?php esc_html_e( 'Password', 'ambassadorhub' ); ?></label>
							<input type="password" name="password" id="ambh-cff-login-password" required />
						</p>
						<p>
							<button type="submit" class="ambh-cff-auth__button"><?php esc_html_e( 'Login', 'ambassadorhub' ); ?></button>
						</p>
					</form>
				</div>

			</div>
		</div>
		<?php
		return (string) ob_get_clean();
	}

	/**
	 * Map an ambh_error query param to a human-readable message for the auth forms.
	 *
	 * @param string $code Error code from the query string.
	 *
	 * @return string Translated error message.
	 */
	private static function auth_error_message( string $code ): string {
		$messages = array(
			'invalid_nonce'  => __( 'Security check failed, please try again.', 'ambassadorhub' ),
			'missing_fields' => __( 'Please fill in all required fields.', 'ambassadorhub' ),
			'weak_password'  => __( 'Password must be at least 8 characters with an uppercase letter, a number, and a special character.', 'ambassadorhub' ),
			'email_exists'   => __( 'This email is already registered. Please log in instead.', 'ambassadorhub' ),
			'create_failed'  => __( 'Could not create your account. Please try again.', 'ambassadorhub' ),
			'login_failed'   => __( 'Invalid email or password.', 'ambassadorhub' ),
		);
		return $messages[ $code ] ?? __( 'Something went wrong. Please try again.', 'ambassadorhub' );
	}

	/**
	 * Enqueue the frontend script/styles and print the one-time global JS
	 * config (window.ambhUserId / window.ambhApiBase / window.ambhFundraiserFormConfig).
	 *
	 * Deliberately takes no per-instance context: this only ever runs once per
	 * page load (see $global_data_printed), so any data that varies between
	 * block instances (e.g. edit_data) belongs in the per-instance render —
	 * see templates/wrapper.php, which renders it as data-* attributes instead.
	 *
	 * @return void
	 */
	private static function enqueue_frontend(): void {
		$handle = 'ambh-create-fundraiser-form-frontend';

		wp_enqueue_script( $handle );
		FundraiserSettingsManager::enqueue_currency_input_assets();

		/**
		 * Fires when the Create Fundraiser Form frontend script is enqueued.
		 * Add-ons can hook here to enqueue companion scripts that extend the form.
		 *
		 * @param string $handle The registered script handle for frontend.js.
		 */
		do_action( 'ambh_enqueue_fundraiser_create_form_scripts', $handle );

		if ( ! self::$global_data_printed ) {
			self::$global_data_printed = true;

			/**
			 * Fields included in the POST body when creating a fundraiser.
			 * Add-ons can append keys to extend what gets sent.
			 *
			 * @param string[] $fields Field keys.
			 */
			$create_fields = apply_filters(
				'ambh_fundraiser_create_submit_fields',
				array(
					'title',
					'content',
					'target_amount',
					'parent_id',
					'is_group',
					'allow_nested_team',
					'teams_enabled',
					'end_date',
				)
			);

			/**
			 * Fields included in the PATCH body when editing a fundraiser.
			 * Add-ons can append keys to extend what gets sent.
			 *
			 * @param string[] $fields Field keys.
			 */
			$edit_fields = apply_filters(
				'ambh_fundraiser_edit_submit_fields',
				array(
					'title',
					'content',
					'target_amount',
					'end_date',
				)
			);

			wp_add_inline_script(
				$handle,
				'window.ambhUserId = ' . (int) get_current_user_id() . ';'
				. 'window.ambhApiBase = ' . wp_json_encode( rtrim( rest_url(), '/' ) ) . ';'
				. 'window.ambhFundraiserFormConfig = ' . wp_json_encode(
					array(
						'createFields' => array_values( $create_fields ),
						'editFields'   => array_values( $edit_fields ),
					)
				) . ';',
				'before'
			);
		}
	}
}
