<?php
/**
 * Join Team Block
 *
 * Renders the token-redemption page for team invitations. Handles both
 * unauthenticated visitors (shows CTAs linking to signup/login) and
 * authenticated users (consumes the token, creates the child fundraiser,
 * and redirects to the account page).
 *
 * @package AmbassadorHub\Fundraisers\Blocks\JoinTeam
 */

namespace AmbassadorHub\Fundraisers\Blocks\JoinTeam;

use AmbassadorHub\Accounts\Admin\Settings\SettingsManager as AccountsSettings;
use AmbassadorHub\Accounts\Roles;
use AmbassadorHub\Fundraisers\FundraisersModule;
use AmbassadorHub\Fundraisers\Invite\InviteManager;

use function add_action;
use function register_block_type;

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

/**
 * Join Team block handler.
 */
class Block {

	/**
	 * Register hooks.
	 */
	public static function init(): void {
		add_action( 'init', array( self::class, 'register_block' ) );
	}

	/**
	 * Register the Gutenberg block type.
	 */
	public static function register_block(): void {
		register_block_type(
			__DIR__,
			array(
				'render_callback' => array( self::class, 'render' ),
			)
		);
	}

	/**
	 * Render the block.
	 *
	 * @param array  $attributes Block attributes (unused).
	 * @param string $content    Inner content (unused).
	 *
	 * @return string HTML output.
	 */
	public static function render( array $attributes, string $content ): string { // phpcs:ignore Generic.CodeAnalysis.UnusedFunctionParameter.FoundAfterLastUsed -- required by WP block render_callback signature
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- token is validated cryptographically.
		$token = isset( $_GET['invite_token'] ) ? sanitize_text_field( wp_unslash( $_GET['invite_token'] ) ) : '';

		if ( empty( $token ) ) {
			return self::render_error( __( 'This invitation link is invalid.', 'ambassadorhub' ) );
		}

		$invite = InviteManager::get_invite( $token );
		if ( null === $invite ) {
			return self::render_error( __( 'This invitation has expired or is invalid.', 'ambassadorhub' ) );
		}

		$team   = get_post( $invite['team_id'] );
		$sender = get_userdata( $invite['sender_id'] );

		if ( ! $team || FundraisersModule::POST_TYPE !== $team->post_type ) {
			return self::render_error( __( 'This invitation has expired or is invalid.', 'ambassadorhub' ) );
		}

		$team_name   = get_the_title( $team );
		$sender_name = $sender ? ( $sender->first_name ? $sender->first_name : $sender->display_name ) : get_bloginfo( 'name' );

		if ( ! is_user_logged_in() ) {
			return self::render_guest_view( $token, $invite, $team_name, $sender_name );
		}

		return self::process_join( $token, $invite, $team_name );
	}

	/**
	 * Render the invitation page for unauthenticated visitors.
	 *
	 * @param string $token       Invitation token.
	 * @param array  $invite      Invite data.
	 * @param string $team_name   Team fundraiser title.
	 * @param string $sender_name Display name of the person who sent the invite.
	 *
	 * @return string HTML.
	 */
	private static function render_guest_view(
		string $token,
		array $invite,
		string $team_name,
		string $sender_name
	): string {
		$signup_page_url = AccountsSettings::get_login_page_url();
		$site_name       = get_bloginfo( 'name' );

		// Build the URL that the signup/login page will redirect back to after auth.
		// Pass $current_url directly — add_query_arg handles the URL encoding.
		$permalink   = get_permalink();
		$current_url = add_query_arg( 'invite_token', $token, $permalink ? $permalink : home_url( '/' ) );

		$btn_label = 'join' === $invite['type']
			? __( 'Join the team', 'ambassadorhub' )
			: __( 'Create your account', 'ambassadorhub' );

		$btn_form  = 'join' === $invite['type'] ? 'login' : 'signup';
		$btn_query = array(
			'redirect_to' => $current_url,
			'ambh_form'   => $btn_form,
		);
		if ( 'new' === $invite['type'] ) {
			$btn_query['ambh_fn']    = $invite['first_name'];
			$btn_query['ambh_email'] = $invite['email'];
		}
		$btn_url = add_query_arg( $btn_query, $signup_page_url );

		$btn_style = 'display:inline-block;padding:12px 28px;background-color:#0073aa;color:#ffffff;'
			. 'font-family:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,Arial,sans-serif;'
			. 'font-size:15px;font-weight:600;text-decoration:none;border-radius:3px;';

		ob_start();
		?>
		<div class="ambh-join-team">
			<p class="ambh-join-team__intro">
				<?php
				echo esc_html(
					sprintf(
						/* translators: 1: sender name, 2: team name, 3: site name */
						__( '%1$s has invited you to join %2$s on %3$s.', 'ambassadorhub' ),
						$sender_name,
						$team_name,
						$site_name
					)
				);
				?>
			</p>
			<p style="text-align:center;margin:28px 0;">
				<a href="<?php echo esc_url( $btn_url ); ?>" style="<?php echo esc_attr( $btn_style ); ?>">
					<?php echo esc_html( $btn_label ); ?>
				</a>
			</p>
			<?php if ( 'new' === $invite['type'] ) : ?>
				<p style="text-align:center;font-size:13px;color:#787c82;">
					<?php esc_html_e( 'Already have an account?', 'ambassadorhub' ); ?>
					<a href="
					<?php
					echo esc_url(
						add_query_arg(
							array(
								'redirect_to' => $current_url,
								'ambh_form'   => 'login',
							),
							$signup_page_url
						)
					);
					?>
								">
						<?php esc_html_e( 'Log in', 'ambassadorhub' ); ?>
					</a>
				</p>
			<?php endif; ?>
		</div>
		<?php
		return (string) ob_get_clean();
	}

	/**
	 * Process token redemption for a logged-in user.
	 *
	 * Consumes the token, creates a child fundraiser under the team, and
	 * redirects to the account page. Returns an error string only when
	 * fundraiser creation fails (redirects otherwise).
	 *
	 * @param string $token     Invitation token.
	 * @param array  $invite    Invite data.
	 * @param string $team_name Team fundraiser title (used as fallback title).
	 *
	 * @return string Error HTML (only reached on wp_insert_post failure).
	 */
	private static function process_join( string $token, array $invite, string $team_name ): string {
		$user_id = get_current_user_id();
		$team_id = (int) $invite['team_id'];

		// Check whether the user is already a member of this team.
		$existing = get_posts(
			array(
				'post_type'      => FundraisersModule::POST_TYPE,
				'post_parent'    => $team_id,
				'author'         => $user_id,
				'post_status'    => 'any',
				'posts_per_page' => 1,
				'fields'         => 'ids',
			)
		);

		// Token is always consumed (one-time use) before any early return.
		InviteManager::consume( $token, $invite );

		if ( ! empty( $existing ) ) {
			wp_safe_redirect( add_query_arg( 'ambh_joined_team', '1', AccountsSettings::get_account_page_url() ) );
			exit;
		}

		// Ensure the user has the ambassador role.
		$user = new \WP_User( $user_id );
		if ( ! $user->has_cap( Roles::ROLE_AMBASSADOR ) ) {
			$user->set_role( Roles::ROLE_AMBASSADOR );
		}

		// Build child fundraiser title from the user's first name.
		$user_data    = get_userdata( $user_id );
		$display_name = $user_data ? ( $user_data->first_name ? $user_data->first_name : $user_data->display_name ) : '';

		$fundraiser_title = $display_name
			/* translators: %s: member's first or display name */
			? sprintf( __( "%s's fundraiser", 'ambassadorhub' ), $display_name )
			: $team_name;

		$new_id = wp_insert_post(
			array(
				'post_title'  => $fundraiser_title,
				'post_type'   => FundraisersModule::POST_TYPE,
				'post_status' => 'publish',
				'post_parent' => $team_id,
				'post_author' => $user_id,
			),
			true
		);

		if ( is_wp_error( $new_id ) ) {
			return self::render_error(
				__( 'Something went wrong while creating your fundraiser. Please contact the site administrator.', 'ambassadorhub' )
			);
		}

		// Trigger the "fundraiser published" event so the welcome email fires.
		do_action( 'ambh_fundraiser_published', $new_id );

		wp_safe_redirect( add_query_arg( 'ambh_joined_team', '1', AccountsSettings::get_account_page_url() ) );
		exit;
	}

	/**
	 * Render a generic error message.
	 *
	 * @param string $message Translated error text.
	 * @return string
	 */
	private static function render_error( string $message ): string {
		return '<div class="ambh-join-team ambh-join-team--error"><p>' . esc_html( $message ) . '</p></div>';
	}
}
