<?php
/**
 * Fundraiser Stats / Detail Meta Boxes
 *
 * Registers the meta boxes shown on the fundraiser stats/detail page.
 * The rendering methods for donations and child fundraisers live in MetaBoxes.php
 *
 * @package AmbassadorHub\Fundraisers\Admin
 */

namespace AmbassadorHub\Fundraisers\Admin;

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

use AmbassadorHub\Fundraisers\FundraisersHelpers;
use AmbassadorHub\Admin\Charts\ChartRenderer;
use AmbassadorHub\Admin\InlineAssets;
use AmbassadorHub\Donations\DonationsModule;
use AmbassadorHub\Fundraisers\FundraisersModule;
use AmbassadorHub\Fundraisers\Admin\Settings\SettingsManager as FundraiserSettingsManager;

/**
 * Registers and renders meta boxes shown on the fundraiser detail/stats page.
 */
final class Stats {

	/**
	 * Initialize stats meta box hooks.
	 *
	 * @return void
	 */
	public static function init(): void {
		add_action( 'add_meta_boxes', array( self::class, 'register_stat_metaboxes' ) );

		// Inline CSS for the donations chart meta box — must be enqueued early
		// enough for admin_print_styles, so hooked on admin_enqueue_scripts rather
		// than called from the meta box render callback itself.
		add_action( 'admin_enqueue_scripts', array( self::class, 'enqueue_chart_metabox_style' ) );
	}

	/**
	 * Enqueue the inline CSS used by the donations chart meta box.
	 *
	 * Hooked on 'admin_enqueue_scripts', which fires early enough for
	 * wp_add_inline_style() to still be picked up by admin_print_styles.
	 *
	 * @return void
	 */
	public static function enqueue_chart_metabox_style(): void {
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$page            = isset( $_GET['page'] ) ? sanitize_key( $_GET['page'] ) : '';
		$stats_page_slug = FundraisersModule::STATS_PAGE_SLUG;

		if ( ! $page || $stats_page_slug !== $page ) {
			return;
		}

		InlineAssets::style(
			'#ambh_fundraiser_donations_chart .ambh-dashboard__section { background: transparent; border: none; padding: 0; margin: 0; }
			#ambh_fundraiser_donations_chart .ambh-dashboard__section-title { display: none; }
			#ambh_fundraiser_donations_chart .ambh-dashboard__graph { height: 420px; }'
		);
	}

	/**
	 * Register meta boxes for the fundraiser stats/detail page.
	 *
	 * Only fires when the `page` query var matches the fundraiser stats slug, so
	 *
	 * @return void
	 */
	public static function register_stat_metaboxes(): void {
		// @phpstan-ignore-next-line
		$page            = isset( $_GET['page'] ) ? sanitize_key( $_GET['page'] ) : ''; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only GET parameter for stats page routing.
		$stats_page_slug = FundraisersModule::STATS_PAGE_SLUG;

		if ( ! $page || $stats_page_slug !== $page ) {
			return;
		}

		// @phpstan-ignore-next-line
		$post_id = isset( $_GET['post_id'] ) ? (int) $_GET['post_id'] : 0; // phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only GET parameter for stats display.
		if ( ! $post_id ) {
			return;
		}

		$screen    = get_current_screen();
		$screen_id = $screen ? $screen->id : $stats_page_slug;

		// Statistics (KPIs + chart).
		add_meta_box(
			'ambh_fundraiser_donations_chart',
			__( 'Statistics', 'ambassadorhub' ),
			array( self::class, 'render_donations_chart_metabox' ),
			$screen_id,
			'normal',
			'high'
		);

		// Teams (child fundraisers) — shown before donations.
		add_meta_box(
			'fundraiser_children',
			__( 'Teams', 'ambassadorhub' ),
			array( MetaBoxes::class, 'render_children_meta_box' ),
			$screen_id,
			'normal',
			'default'
		);

		// Donations (read-only display) — rendering delegated to MetaBoxes.
		add_meta_box(
			'fundraiser_donations',
			__( 'Donations', 'ambassadorhub' ),
			array( MetaBoxes::class, 'render_donations_meta_box' ),
			$screen_id,
			'normal',
			'default'
		);

		add_meta_box(
			'fundraiser_children',
			__( 'Child Fundraisers', 'ambassadorhub' ),
			array( MetaBoxes::class, 'render_children_meta_box' ),
			$screen_id,
			'normal',
			'default'
		);
	}

	/**
	 * Render the donations-over-time chart meta box.
	 *
	 * Uses ChartRenderer (shared utility) to output a Chart.js line chart of
	 * monthly donation amounts and donor counts for this fundraiser.
	 *
	 * @param \WP_Post $post Current fundraiser post.
	 * @return void
	 */
	public static function render_donations_chart_metabox( \WP_Post $post ): void {
		$all_ids    = array_merge( array( $post->ID ), self::get_descendant_fundraiser_ids( $post->ID ) );
		$kpis       = self::get_kpi_data( $all_ids );
		$chart_data = self::get_chart_data( $all_ids );
		?>
		<!-- KPI boxes above the grpaph -->
		<div class="ambh-kpi-grid" style="margin-bottom: 20px;">
			<div class="ambh-kpi-card">
				<span class="ambh-kpi-card__icon dashicons dashicons-clipboard"></span>
				<div class="ambh-kpi-card__body">
					<span class="ambh-kpi-card__value"><?php echo esc_html( number_format_i18n( $kpis['count'] ) ); ?></span>
					<span class="ambh-kpi-card__label"><?php esc_html_e( 'Number of donations', 'ambassadorhub' ); ?></span>
				</div>
			</div>
			<div class="ambh-kpi-card">
				<span class="ambh-kpi-card__icon dashicons dashicons-chart-bar"></span>
				<div class="ambh-kpi-card__body">
					<span class="ambh-kpi-card__value"><?php echo esc_html( FundraiserSettingsManager::format_currency( $kpis['average'] ) ); ?></span>
					<span class="ambh-kpi-card__label"><?php esc_html_e( 'Average donation', 'ambassadorhub' ); ?></span>
				</div>
			</div>
			<div class="ambh-kpi-card">
				<span class="ambh-kpi-card__icon dashicons dashicons-money-alt"></span>
				<div class="ambh-kpi-card__body">
					<span class="ambh-kpi-card__value"><?php echo esc_html( FundraiserSettingsManager::format_currency( $kpis['total'] ) ); ?></span>
					<span class="ambh-kpi-card__label"><?php esc_html_e( 'Total donated', 'ambassadorhub' ); ?></span>
				</div>
			</div>
		</div>

		<?php
		$target_amount  = (float) get_post_meta( $post->ID, '_ambh_target_amount', true );
		$progress_pct   = ( $target_amount > 0 ) ? min( 100.0, ( $kpis['total'] / $target_amount ) * 100 ) : 0.0;
		$end_date       = FundraisersHelpers::get_effective_end_date_gmt( $post->ID );
		$days_remaining = $end_date ? (int) ceil( ( strtotime( (string) $end_date ) - time() ) / DAY_IN_SECONDS ) : null;
		$is_closed      = ! FundraisersHelpers::fundraiser_is_open( $post->ID );
		?>

		<div style="display: grid; grid-template-columns: 1fr auto; gap: 16px; align-items: stretch; margin-bottom: 24px;">

			<div style="background: #fff; border: 1px solid <?php echo $progress_pct >= 100 ? '#f0b429' : '#c3c4c7'; ?>; border-radius: 4px; padding: 16px; <?php echo $progress_pct >= 100 ? 'background: linear-gradient(135deg,#fffbea 0%,#fff 100%);' : ''; ?>">
				<div style="display: flex; justify-content: space-between; margin-bottom: 8px; font-size: 13px;">
					<span><?php echo esc_html( FundraiserSettingsManager::format_currency( $kpis['total'] ) . ' ' . __( 'raised', 'ambassadorhub' ) ); ?></span>
					<span><?php echo esc_html( __( 'Goal:', 'ambassadorhub' ) . ' ' . ( $target_amount > 0 ? FundraiserSettingsManager::format_currency( $target_amount ) : '—' ) ); ?></span>
				</div>
				<?php if ( $progress_pct >= 100 ) : ?>
				<div style="background: #f5e6c0; border-radius: 4px; height: 20px; overflow: hidden;">
					<div style="background: linear-gradient(90deg,#f6d365 0%,#fda085 50%,#f6d365 100%); height: 100%; width: 100%;"></div>
				</div>
				<p style="margin: 8px 0 0; font-size: 12px; color: #8a5f00; font-weight: 600;">
					<span class="dashicons dashicons-star-filled" style="font-size: 14px; width: 14px; height: 14px; vertical-align: middle; color: #f0b429;"></span>
					<?php esc_html_e( 'Goal reached!', 'ambassadorhub' ); ?>
				</p>
				<?php else : ?>
				<div style="background: #e0e0e0; border-radius: 4px; height: 16px; overflow: hidden;">
					<div style="background: #0073aa; height: 100%; width: <?php echo esc_attr( number_format( $progress_pct, 2 ) ); ?>%; transition: width 0.3s ease;"></div>
				</div>
					<?php if ( $target_amount > 0 ) : ?>
				<p style="margin: 8px 0 0; font-size: 12px; color: #666;"><?php echo esc_html( number_format( $progress_pct, 1 ) . '% ' . __( 'of goal reached', 'ambassadorhub' ) ); ?></p>
				<?php endif; ?>
				<?php endif; ?>
			</div>

			<div class="ambh-kpi-card" style="height: 100%; box-sizing: border-box;<?php echo $is_closed ? ' background: #f6f7f7; border-color: #dcdcde; opacity: 0.55;' : ''; ?>">
				<span class="ambh-kpi-card__icon dashicons dashicons-calendar-alt"></span>
				<div class="ambh-kpi-card__body">
					<?php if ( $is_closed ) : ?>
						<span class="ambh-kpi-card__value">0</span>
						<span class="ambh-kpi-card__label"><?php esc_html_e( 'Closed', 'ambassadorhub' ); ?></span>
					<?php elseif ( null === $days_remaining ) : ?>
						<span class="ambh-kpi-card__value">—</span>
						<span class="ambh-kpi-card__label"><?php esc_html_e( 'No end date set', 'ambassadorhub' ); ?></span>
					<?php elseif ( $days_remaining <= 0 ) : ?>
						<span class="ambh-kpi-card__value"><?php esc_html_e( 'Ended', 'ambassadorhub' ); ?></span>
						<span class="ambh-kpi-card__label"><?php esc_html_e( 'Fundraiser ended', 'ambassadorhub' ); ?></span>
					<?php else : ?>
						<span class="ambh-kpi-card__value"><?php echo esc_html( (string) $days_remaining ); ?></span>
						<span class="ambh-kpi-card__label"><?php esc_html_e( 'Days remaining', 'ambassadorhub' ); ?></span>
					<?php endif; ?>
				</div>
			</div>

		</div>

		<!-- Render the graph or a placeholder -->
		<?php if ( 0 === $kpis['count'] ) : ?>
			<p style="margin: 8px 0;"><?php esc_html_e( 'No completed donations yet.', 'ambassadorhub' ); ?></p>
		<?php else : ?>
			<?php
			ChartRenderer::render(
				__( 'Fundraiser Statistics', 'ambassadorhub' ),
				'ambh-fundraiser-chart-' . $post->ID,
				array(
					'type'    => 'bar',
					'data'    => array(
						'labels'   => $chart_data['labels'],
						'datasets' => array(
							array(
								'type'        => 'bar',
								/* translators: %s: currency symbol */
								'label'       => sprintf( __( 'Amount donated (%s)', 'ambassadorhub' ), FundraiserSettingsManager::get_currency_symbol() ),
								'data'        => $chart_data['amounts'],
								'borderWidth' => 1,
								'yAxisID'     => 'y',
							),
							array(
								'type'        => 'line',
								'label'       => __( 'Number of donors', 'ambassadorhub' ),
								'data'        => $chart_data['donors'],
								'borderWidth' => 3,
								'tension'     => 0,
								'fill'        => false,
								'yAxisID'     => 'y1',
							),
						),
					),
					'options' => array(
						'scales' => array(
							'y'  => array(
								'beginAtZero' => true,
								'position'    => 'left',
							),
							'y1' => array(
								'beginAtZero' => true,
								'position'    => 'right',
								'grid'        => array( 'drawOnChartArea' => false ),
							),
						),
					),
				)
			);
			?>
		<?php endif; ?>
		<?php
	}

	/**
	 * Return IDs of all descendant fundraisers (recursive via post_parent).
	 *
	 * @param int $fundraiser_id Root fundraiser post ID.
	 * @return int[]
	 */
	private static function get_descendant_fundraiser_ids( int $fundraiser_id ): array {
		$all      = array();
		$children = get_posts(
			array(
				'post_type'      => FundraisersModule::POST_TYPE,
				'post_parent'    => $fundraiser_id,
				'posts_per_page' => -1,
				'fields'         => 'ids',
				'post_status'    => 'any',
			)
		);
		foreach ( $children as $child_id ) {
			$all[] = (int) $child_id;
			$all   = array_merge( $all, self::get_descendant_fundraiser_ids( (int) $child_id ) );
		}
		return $all;
	}

	private static function get_kpi_data( array $fundraiser_ids ): array {
		global $wpdb;
		$table = esc_sql( DonationsModule::get_table_name() );

		if ( empty( $fundraiser_ids ) ) {
			return array(
				'count'   => 0,
				'total'   => 0.0,
				'average' => 0.0,
			);
		}

		$placeholders = implode( ',', array_fill( 0, count( $fundraiser_ids ), '%d' ) );
		$args         = array_merge( array( 'completed' ), $fundraiser_ids );

		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		$row = $wpdb->get_row(
			$wpdb->prepare(
				"SELECT COUNT(*) AS total_count, SUM(amount) AS total_amount, AVG(amount) AS avg_amount
				FROM {$table}
				WHERE status = %s AND fundraiser_id IN ({$placeholders})",
				...$args
			)
		);
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared

		return array(
			'count'   => (int) ( $row->total_count ?? 0 ),
			'total'   => (float) ( $row->total_amount ?? 0 ),
			'average' => (float) ( $row->avg_amount ?? 0 ),
		);
	}

	/**
	 * Get monthly donation amounts and donor counts for the past 12 months,
	 * scoped to a single fundraiser.
	 *
	 * @param int $fundraiser_id Fundraiser post ID.
	 * @return array{labels: string[], amounts: float[], donors: int[]}
	 */
	private static function get_chart_data( array $fundraiser_ids ): array {
		global $wpdb;
		$table = esc_sql( DonationsModule::get_table_name() );

		if ( empty( $fundraiser_ids ) ) {
			return array(
				'labels'  => array(),
				'amounts' => array(),
				'donors'  => array(),
			);
		}

		$placeholders = implode( ',', array_fill( 0, count( $fundraiser_ids ), '%d' ) );
		$args         = array_merge( array( 'completed' ), $fundraiser_ids, array( gmdate( 'Y-m-01', strtotime( '-11 months' ) ) ) );

		// phpcs:disable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared, WordPress.DB.PreparedSQLPlaceholders.ReplacementsWrongNumber
		$rows = $wpdb->get_results(
			$wpdb->prepare(
				"SELECT
					DATE_FORMAT(created_at, '%%Y-%%m') AS month,
					SUM(amount)                        AS total_amount,
					COUNT(DISTINCT donor_id)           AS total_donors
				FROM {$table}
				WHERE status = %s
				  AND fundraiser_id IN ({$placeholders})
				  AND created_at >= %s
				GROUP BY month
				ORDER BY month ASC",
				...$args
			)
		);
		// phpcs:enable WordPress.DB.DirectDatabaseQuery.DirectQuery, WordPress.DB.DirectDatabaseQuery.NoCaching, WordPress.DB.PreparedSQL.InterpolatedNotPrepared

		$row_map = array();
		foreach ( (array) $rows as $row ) {
			$row_map[ $row->month ] = array(
				'amount' => (float) $row->total_amount,
				'donors' => (int) $row->total_donors,
			);
		}

		$labels  = array();
		$amounts = array();
		$donors  = array();

		for ( $i = 11; $i >= 0; $i-- ) {
			$key       = gmdate( 'Y-m', strtotime( "-{$i} months" ) );
			$labels[]  = gmdate( 'M Y', strtotime( "-{$i} months" ) );
			$amounts[] = $row_map[ $key ]['amount'] ?? 0.0;
			$donors[]  = $row_map[ $key ]['donors'] ?? 0;
		}

		return compact( 'labels', 'amounts', 'donors' );
	}
}
