<?php
/**
 * Ambassadors Block
 *
 * Displays a card grid of individual fundraisers who are direct members of the
 * current team. Only renders on team fundraiser pages with at least one
 * published member. Each card shows the member's profile picture, name, amount
 * raised, target, and a progress bar.
 *
 * @package AmbassadorHub\Fundraisers\Blocks\Ambassadors
 */

namespace AmbassadorHub\Fundraisers\Blocks\Ambassadors;

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

// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.UnfinishedPrepare

use AmbassadorHub\Accounts\ProfilePicture;
use AmbassadorHub\Donations\DonationsModule;
use AmbassadorHub\Fundraisers\Admin\Settings\SettingsManager;
use AmbassadorHub\Fundraisers\FundraisersModule;

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

	private const META_TARGET_AMOUNT = '_ambh_target_amount';

	// -------------------------------------------------------------------------
	// Boot
	// -------------------------------------------------------------------------

	public static function init(): void {
		add_action( 'init', array( self::class, 'register_block' ) );
	}

	// -------------------------------------------------------------------------
	// Registration
	// -------------------------------------------------------------------------

	public static function register_block(): void {
		$block_dir = AMBASSADOR_HUB_PATH . 'src/Fundraisers/Blocks/Ambassadors/';
		$block_url = AMBASSADOR_HUB_URL . 'src/Fundraisers/Blocks/Ambassadors/';

		$script_file = $block_dir . 'index.js';
		if ( file_exists( $script_file ) ) {
			wp_register_script(
				'ambh-ambassadors-block',
				$block_url . 'index.js',
				array( 'wp-blocks', 'wp-i18n', 'wp-element', 'wp-block-editor', 'wp-components' ),
				(string) filemtime( $script_file ),
				true
			);
		}

		$style_file = $block_dir . 'style.css';
		wp_register_style(
			'ambh-ambassadors',
			$block_url . 'style.css',
			array(),
			file_exists( $style_file ) ? (string) filemtime( $style_file ) : AMBASSADOR_HUB_VERSION
		);

		$block_args = array(
			'style'           => 'ambh-ambassadors',
			'render_callback' => array( self::class, 'render_block' ),
		);
		if ( file_exists( $script_file ) ) {
			$block_args['editor_script'] = 'ambh-ambassadors-block';
		}

		register_block_type( $block_dir, $block_args );
	}

	// -------------------------------------------------------------------------
	// Rendering
	// -------------------------------------------------------------------------

	public static function render_block( array $attributes = array() ): string {
		if ( defined( 'REST_REQUEST' ) && REST_REQUEST ) {
			return '<div class="fundraiser-ambassadors-block ambh-block-preview" style="padding:16px;background:#f0f0f1;border:1px solid #ddd;text-align:center;">'
				. esc_html__( 'Team Members — renders on the frontend for team fundraiser pages.', 'ambassadorhub' )
				. '</div>';
		}

		$post = get_post();
		if ( ! $post || FundraisersModule::POST_TYPE !== get_post_type( $post ) ) {
			return '';
		}

		if ( '1' !== get_post_meta( $post->ID, FundraisersModule::META_IS_TEAM, true ) ) {
			return '';
		}

		$members = self::get_members( (int) $post->ID );
		if ( empty( $members ) ) {
			return '';
		}

		$title      = trim( (string) ( $attributes['title'] ?? '' ) );
		$title_html = '' !== $title
			? '<h2 class="ambh-block-title">' . esc_html( $title ) . '</h2>'
			: '';

		$cards = '';
		foreach ( $members as $member ) {
			$cards .= self::render_card( $member );
		}

		return '<div class="fundraiser-ambassadors-block">'
			. $title_html
			. '<div class="ambassadors-grid">' . $cards . '</div>'
			. '</div>';
	}

	// -------------------------------------------------------------------------
	// Card rendering
	// -------------------------------------------------------------------------

	private static function render_card( array $member ): string {
		$raised = $member['total_raised'];
		$target = $member['target_amount'];
		$pct    = $target > 0.0 ? min( 100, (int) round( ( $raised / $target ) * 100 ) ) : 0;
		$url    = esc_url( $member['permalink'] );

		if ( '' !== $member['avatar_url'] ) {
			$avatar_inner = '<img src="' . esc_url( $member['avatar_url'] ) . '" alt="' . esc_attr( $member['title'] ) . '" loading="lazy">';
		} else {
			$avatar_inner = '<svg viewBox="0 0 24 24" fill="currentColor" xmlns="http://www.w3.org/2000/svg" aria-hidden="true">'
				. '<circle cx="12" cy="8" r="4"/>'
				. '<path d="M4 20c0-4 3.6-7 8-7s8 3 8 7"/>'
				. '</svg>';
		}

		$raised_row = '<div class="stat-row">'
			. '<span class="stat-label">' . esc_html__( 'Raised', 'ambassadorhub' ) . '</span>'
			. '<span class="stat-value">' . esc_html( SettingsManager::format_currency( $raised, 0 ) ) . '</span>'
			. '</div>';

		$target_row = '';
		if ( $target > 0.0 ) {
			$target_row = '<div class="stat-row">'
				. '<span class="stat-label">' . esc_html__( 'Target', 'ambassadorhub' ) . '</span>'
				. '<span class="stat-value">' . esc_html( SettingsManager::format_currency( $target, 0 ) ) . '</span>'
				. '</div>';
		}

		$progress_html = '';
		if ( $target > 0.0 ) {
			$progress_html = '<div class="progress-bar">'
				. '<div class="progress-fill" style="width:' . esc_attr( $pct . '%' ) . ';"></div>'
				. '</div>'
				. '<p class="progress-text">' . esc_html( $pct . '%' ) . '</p>';
		}

		return '<article class="ambassador-card">'
			. '<a href="' . $url . '" class="ambassador-avatar" tabindex="-1" aria-hidden="true">' . $avatar_inner . '</a>'
			. '<h3 class="ambassador-name"><a href="' . $url . '">' . esc_html( $member['title'] ) . '</a></h3>'
			. '<div class="ambassador-stats">' . $raised_row . $target_row . $progress_html . '</div>'
			. '</article>';
	}

	// -------------------------------------------------------------------------
	// Data
	// -------------------------------------------------------------------------

	/**
	 * Fetch direct individual (non-team) members of a team, sorted by amount raised.
	 *
	 * @param int $team_id Team fundraiser post ID.
	 *
	 * @return array[]
	 */
	private static function get_members( int $team_id ): array {
		$posts = get_posts(
			array(
				'post_type'      => FundraisersModule::POST_TYPE,
				'post_parent'    => $team_id,
				'post_status'    => 'publish',
				'posts_per_page' => -1,
				'orderby'        => 'title',
				'order'          => 'ASC',
				'meta_query'     => array( // phpcs:ignore WordPress.DB.SlowDBQuery.slow_db_query_meta_query
				'relation' => 'OR',
				array(
					'key'     => FundraisersModule::META_IS_TEAM,
					'compare' => 'NOT EXISTS',
				),
				array(
					'key'     => FundraisersModule::META_IS_TEAM,
					'value'   => '1',
					'compare' => '!=',
				),
				),
			)
		);

		if ( empty( $posts ) ) {
			return array();
		}

		$ids    = array_map( static fn( $p ): int => (int) $p->ID, $posts );
		$raised = self::get_raised_by_ids( $ids );

		$members = array();
		foreach ( $posts as $post ) {
			$id      = (int) $post->ID;
			$user_id = (int) $post->post_author;
			$target  = (float) get_post_meta( $id, self::META_TARGET_AMOUNT, true );

			// Prefer the ambassador's account profile picture; fall back to
			// Gravatar. External service call — see readme.txt's "External
			// Services" section: sends the user's email (hashed by WordPress
			// core's get_avatar_url()) only when no custom picture is set.
			$avatar_url = ProfilePicture::get_profile_picture_url( $user_id );
			if ( ! $avatar_url ) {
				$avatar_url = (string) get_avatar_url( $user_id, array( 'size' => 150 ) );
			}

			$members[] = array(
				'id'            => $id,
				'title'         => $post->post_title,
				'permalink'     => (string) get_permalink( $id ),
				'avatar_url'    => (string) $avatar_url,
				'total_raised'  => $raised[ $id ] ?? 0.0,
				'target_amount' => $target,
			);
		}

		usort( $members, static fn( array $a, array $b ): int => $b['total_raised'] <=> $a['total_raised'] );

		return $members;
	}

	/**
	 * Batch-fetch completed donation totals for a list of fundraiser IDs.
	 *
	 * @param int[] $ids Fundraiser post IDs.
	 *
	 * @return array<int, float> Map of fundraiser_id → total raised.
	 */
	private static function get_raised_by_ids( array $ids ): array {
		global $wpdb;
		if ( empty( $ids ) ) {
			return array();
		}

		$table        = esc_sql( DonationsModule::get_table_name() );
		$placeholders = implode( ',', array_fill( 0, count( $ids ), '%d' ) );

		$rows = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT fundraiser_id, COALESCE(SUM(amount),0) AS total
				 FROM {$table}
				 WHERE fundraiser_id IN ({$placeholders}) AND status = 'completed'
				 GROUP BY fundraiser_id",
				...$ids
			)
		);

		$result = array_fill_keys( $ids, 0.0 );
		foreach ( $rows as $row ) {
			$result[ (int) $row->fundraiser_id ] = (float) $row->total;
		}
		return $result;
	}
}
