<?php
/**
 * Dashboard Page
 *
 * The main AmbassadorHub overview page shown when clicking the top-level
 * menu item. Displays installation setup steps and KPI statistics.
 *
 * @package AmbassadorHub\Admin\Dashboard
 */

namespace AmbassadorHub\Admin\Dashboard;

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

use AmbassadorHub\Admin\AdminPage;
use AmbassadorHub\Admin\Charts\ChartRenderer;
use AmbassadorHub\Admin\Wizard\SetupWizard;
use AmbassadorHub\Fundraisers\FundraisersModule;
use AmbassadorHub\Accounts\Roles;
use AmbassadorHub\Donors\DonorsModule;
use AmbassadorHub\Donations\DonationsModule;
use AmbassadorHub\Mail\MailerService;

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

/**
 * Dashboard admin page — hooks, rendering, KPIs, and chart data.
 */
final class Dashboard {

	/**
	 * Initialise hooks.
	 *
	 * @return void
	 */
	/**
	 * Transient key for the chart data cache.
	 */
	const CHART_CACHE_KEY = 'ambh_dashboard_chart_data';

	public static function init(): void {

		add_action( 'admin_notices', array( self::class, 'render_header' ), 1 );
		add_action( 'admin_post_ambh_toggle_checklist', array( self::class, 'handle_toggle_checklist' ) );
		add_action( 'admin_post_ambh_dashboard_test_email', array( self::class, 'handle_test_email' ) );

		// Invalidate chart cache whenever a donation changes.
		add_action( 'ambh_donation_created', array( self::class, 'invalidate_chart_cache' ) );
		add_action( 'ambh_donation_updated', array( self::class, 'invalidate_chart_cache' ) );
		add_action( 'ambh_donation_deleted', array( self::class, 'invalidate_chart_cache' ) );
	}

	/**
	 * Delete the cached chart data transient.
	 *
	 * @return void
	 */
	public static function invalidate_chart_cache(): void {
		delete_transient( self::CHART_CACHE_KEY );
	}

	/**
	 * Handle toggling the setup checklist visibility.
	 *
	 * @return void
	 */
	public static function handle_toggle_checklist(): void {
		check_admin_referer( 'ambh_toggle_checklist' );

		if ( ! current_user_can( 'ambh_manage_hub' ) ) {
			wp_die( esc_html__( 'Insufficient permissions.', 'ambassadorhub' ) );
		}

		$collapsed = get_option( 'ambh_checklist_collapsed', '' );
		update_option( 'ambh_checklist_collapsed', $collapsed ? '' : '1', false );

		wp_safe_redirect( admin_url( 'admin.php?page=ambassadorhub' ) );
		exit;
	}

	/**
	 * Send a test email from the dashboard and persist the result.
	 *
	 * @return void
	 */
	public static function handle_test_email(): void {
		check_admin_referer( 'ambh_dashboard_test_email' );

		if ( ! current_user_can( 'ambh_manage_hub' ) ) {
			wp_die( esc_html__( 'Insufficient permissions.', 'ambassadorhub' ) );
		}

		$to         = (string) get_option( 'admin_email', '' );
		$site_name  = get_bloginfo( 'name' );
		$mail_error = null;
		$capture    = static function ( \WP_Error $error ) use ( &$mail_error ): void {
			$mail_error = $error;
		};
		add_action( 'wp_mail_failed', $capture );

		$sent = MailerService::send(
			$to,
			sprintf(
				/* translators: %s: site name */
				__( '[%s] Test email from AmbassadorHub', 'ambassadorhub' ),
				$site_name
			),
			'<p>' . esc_html__( 'If you received this message, your WordPress mail setup is working correctly.', 'ambassadorhub' ) . '</p>',
			__( 'Your WordPress mail setup is working.', 'ambassadorhub' )
		);

		remove_action( 'wp_mail_failed', $capture );

		if ( $mail_error instanceof \WP_Error ) {
			$sent = false;
		}

		if ( $sent ) {
			update_option( 'ambh_email_configured', '1', false );
		}

		$result = array( 'status' => $sent ? 'sent' : 'failed' );
		if ( ! $sent && $mail_error instanceof \WP_Error ) {
			$result['error'] = $mail_error->get_error_message();
		}
		set_transient( 'ambh_dashboard_email_test_' . get_current_user_id(), $result, 60 );

		wp_safe_redirect( admin_url( 'admin.php?page=ambassadorhub' ) );
		exit;
	}

	/**
	 * Render the dashboard header.
	 *
	 * @return void
	 */
	public static function render_header(): void {

		if ( ! current_user_can( 'ambh_manage_hub' ) ) {
			return;
		}

		if ( ! AdminPage::is_page( 'ambassadorhub' ) ) {
			return;
		}

		AdminPage::header(
			esc_html__( 'AmbassadorHub', 'ambassadorhub' ),
			esc_html__( 'Your referral & ambassador program — overview', 'ambassadorhub' )
		);
	}

	/**
	 * Render the dashboard page.
	 *
	 * @return void
	 */
	public static function render(): void {
		if ( ! current_user_can( 'ambh_manage_hub' ) ) {
			wp_die( esc_html__( 'You do not have permission to access this page.', 'ambassadorhub' ) );
		}

		// Show a completion notice after the wizard finishes.
		// phpcs:ignore WordPress.Security.NonceVerification.Recommended -- read-only GET flag, no state change.
		if ( ! empty( $_GET['ambh_wizard_done'] ) ) {
			?>
			<div class="notice notice-success is-dismissible" style="margin:16px 0 0;">
				<p>
					<strong><?php esc_html_e( '🎉 Setup complete!', 'ambassadorhub' ); ?></strong>
					<?php esc_html_e( 'AmbassadorHub is ready to go. You can now create fundraisers and invite ambassadors.', 'ambassadorhub' ); ?>
				</p>
			</div>
			<?php
		}

		$email_test = get_transient( 'ambh_dashboard_email_test_' . get_current_user_id() );
		if ( false !== $email_test ) {
			delete_transient( 'ambh_dashboard_email_test_' . get_current_user_id() );
		}

		$kpis        = self::get_kpis();
		$steps       = self::get_setup_steps();
		$all_done    = ! in_array( false, array_column( $steps, 'done' ), true );
		$done_count  = count( array_filter( $steps, static fn( $s ) => $s['done'] ) );
		$total_count = count( $steps );
		$collapsed   = (bool) get_option( 'ambh_checklist_collapsed', '' );

		if ( is_array( $email_test ) ) {
			if ( 'sent' === ( $email_test['status'] ?? '' ) ) {
				?>
				<div class="notice notice-success is-dismissible" style="margin:16px 0 0;">
					<p>
						<strong><?php esc_html_e( 'Test email sent!', 'ambassadorhub' ); ?></strong>
						<?php esc_html_e( 'Check your inbox to confirm it arrived. Your email setup is now marked as configured.', 'ambassadorhub' ); ?>
					</p>
				</div>
				<?php
			} elseif ( 'failed' === ( $email_test['status'] ?? '' ) ) {
				$error = $email_test['error'] ?? '';
				?>
				<div class="notice notice-error is-dismissible" style="margin:16px 0 0;">
					<p>
						<strong><?php esc_html_e( 'Test email failed.', 'ambassadorhub' ); ?></strong>
						<?php esc_html_e( 'WordPress could not send the email. Install an SMTP plugin such as WP Mail SMTP to fix this.', 'ambassadorhub' ); ?>
						<?php if ( '' !== $error ) : ?>
							<br><code style="font-size:12px;"><?php echo esc_html( $error ); ?></code>
						<?php endif; ?>
					</p>
				</div>
				<?php
			}
		}
		?>

		<div class="wrap">

			<h1 class="hidden"></h1> <!-- Prevent admin notice moved to the h2 position -->

			<!-- KPI cards -->
			<section class="ambh-dashboard__section">
				<h2 class="ambh-dashboard__section-title">
					<?php esc_html_e( 'At a glance', 'ambassadorhub' ); ?>
				</h2>
				<div class="ambh-kpi-grid">
					<?php foreach ( $kpis as $kpi ) : ?>
						<div class="ambh-kpi-card">
							<span class="ambh-kpi-card__icon dashicons <?php echo esc_attr( $kpi['icon'] ); ?>"></span>
							<div class="ambh-kpi-card__body">
								<span class="ambh-kpi-card__value"><?php echo esc_html( $kpi['value'] ); ?></span>
								<span class="ambh-kpi-card__label"><?php echo esc_html( $kpi['label'] ); ?></span>
							</div>
							<?php if ( ! empty( $kpi['url'] ) ) : ?>
								<a class="ambh-kpi-card__link" href="<?php echo esc_url( $kpi['url'] ); ?>">
									<?php esc_html_e( 'View', 'ambassadorhub' ); ?>
									<span class="dashicons dashicons-arrow-right-alt2"></span>
								</a>
							<?php endif; ?>
						</div>
					<?php endforeach; ?>
				</div>
			</section>


			<!-- Donations chart -->
			<?php if ( DonationsModule::count( 'completed' ) > 0 ) : ?>
				<?php self::get_dashboard_chart(); ?>
			<?php endif; ?>

			<!-- Setup checklist -->
			<section class="ambh-dashboard__section ambh-setup-section<?php echo $collapsed ? ' is-collapsed' : ''; ?>">
				<div class="ambh-setup-header">
					<div>
						<h2 class="ambh-dashboard__section-title ambh-dashboard__section-title--no-margin">
							<?php esc_html_e( 'Setup checklist', 'ambassadorhub' ); ?>
						</h2>
						<p class="ambh-setup-header__sub">
							<?php
							echo esc_html(
								sprintf(
									/* translators: 1: completed steps, 2: total steps */
									__( '%1$d of %2$d steps completed', 'ambassadorhub' ),
									$done_count,
									$total_count
								)
							);
							?>
						</p>
					</div>
					<div class="ambh-setup-header__actions">
						<?php if ( $all_done ) : ?>
							<span class="ambh-setup-badge ambh-setup-badge--done">
								<span class="dashicons dashicons-yes-alt"></span>
								<?php esc_html_e( 'All set!', 'ambassadorhub' ); ?>
							</span>
						<?php else : ?>
							<span class="ambh-setup-badge">
								<?php echo esc_html( $done_count . '/' . $total_count ); ?>
							</span>
						<?php endif; ?>
						<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="display:inline;">						<input type="hidden" name="action" value="ambh_wizard_restart">
						<?php wp_nonce_field( 'ambh_wizard_restart' ); ?>
						<button type="submit" class="button button-small">
							<span class="dashicons dashicons-update" style="margin-top:3px;"></span>
							<?php esc_html_e( 'Re-run wizard', 'ambassadorhub' ); ?>
						</button>
					</form>
					<form method="post" action="<?php echo esc_url( admin_url( 'admin-post.php' ) ); ?>" style="display:inline;">							<input type="hidden" name="action" value="ambh_toggle_checklist">
							<?php wp_nonce_field( 'ambh_toggle_checklist' ); ?>
							<button type="submit" class="ambh-setup-toggle" title="<?php echo $collapsed ? esc_attr__( 'Show checklist', 'ambassadorhub' ) : esc_attr__( 'Hide checklist', 'ambassadorhub' ); ?>" aria-expanded="<?php echo $collapsed ? 'false' : 'true'; ?>">
								<span class="dashicons <?php echo $collapsed ? 'dashicons-arrow-down-alt2' : 'dashicons-arrow-up-alt2'; ?>"></span>
							</button>
						</form>
					</div>
				</div>

				<!-- Progress bar -->
				<div class="ambh-progress" role="progressbar" aria-valuenow="<?php echo esc_attr( $done_count ); ?>" aria-valuemin="0" aria-valuemax="<?php echo esc_attr( $total_count ); ?>">
					<div class="ambh-progress__bar" style="width: <?php echo esc_attr( round( ( $done_count / $total_count ) * 100 ) ); ?>%"></div>
				</div>

				<ul class="ambh-setup-list">
					<?php foreach ( $steps as $step ) : ?>
						<li class="ambh-setup-step <?php echo $step['done'] ? 'is-done' : 'is-pending'; ?>">
							<span class="ambh-setup-step__icon dashicons <?php echo $step['done'] ? 'dashicons-yes-alt' : 'dashicons-marker'; ?>"></span>
							<div class="ambh-setup-step__content">
								<strong class="ambh-setup-step__title"><?php echo esc_html( $step['title'] ); ?></strong>
								<?php if ( ! empty( $step['description'] ) ) : ?>
									<span class="ambh-setup-step__desc"><?php echo esc_html( $step['description'] ); ?></span>
								<?php endif; ?>
							</div>
							<?php if ( ! $step['done'] && ! empty( $step['url'] ) ) : ?>
								<a class="button button-small ambh-setup-step__action" href="<?php echo esc_url( $step['url'] ); ?>">
									<?php echo esc_html( $step['action_label'] ?? __( 'Configure', 'ambassadorhub' ) ); ?>
								</a>
							<?php elseif ( ! $step['done'] && ! empty( $step['form_action'] ) ) : ?>
								<form method="post" action="<?php echo esc_url( $step['form_action'] ); ?>" style="display:inline;">
									<?php foreach ( $step['form_hidden'] as $field_name => $field_value ) : ?>
										<input type="hidden" name="<?php echo esc_attr( $field_name ); ?>" value="<?php echo esc_attr( $field_value ); ?>">
									<?php endforeach; ?>
									<?php wp_nonce_field( $step['form_nonce'] ); ?>
									<button type="submit" class="button button-small ambh-setup-step__action">
										<?php echo esc_html( $step['action_label'] ?? __( 'Configure', 'ambassadorhub' ) ); ?>
									</button>
								</form>
							<?php endif; ?>
						</li>
					<?php endforeach; ?>
				</ul>
			</section>

		</div>

		<?php
	}

	// -------------------------------------------------------------------------
	// Setup steps
	// -------------------------------------------------------------------------

	/**
	 * Build the installation setup checklist.
	 *
	 * Each step is an array with keys:
	 *   - title        (string)
	 *   - description  (string|null)
	 *   - done         (bool)
	 *   - url          (string)  — link for the CTA button when not done
	 *   - action_label (string)  — button text
	 *
	 * @return array<int, array<string, mixed>>
	 */
	private static function get_setup_steps(): array {

		$settings_url = admin_url( 'admin.php?page=ambassadorhub-settings' );

		$steps = array(
			array(
				'title'        => __( 'Plugin activated', 'ambassadorhub' ),
				'description'  => __( 'AmbassadorHub is installed and running.', 'ambassadorhub' ),
				'done'         => true,
				'url'          => '',
				'action_label' => '',
			),
			array(
				'title'        => __( 'Email correctly configured', 'ambassadorhub' ),
				'description'  => __( 'Verify that WordPress can send transactional emails (confirmations, invites).', 'ambassadorhub' ),
				'done'         => (bool) get_option( 'ambh_email_configured', '' ),
				'form_action'  => admin_url( 'admin-post.php' ),
				'form_nonce'   => 'ambh_dashboard_test_email',
				'form_hidden'  => array( 'action' => 'ambh_dashboard_test_email' ),
				'action_label' => __( 'Send test email', 'ambassadorhub' ),
			),
			array(
				'title'        => __( 'Configure a payment provider (PSP)', 'ambassadorhub' ),
				'description'  => __( 'Connect a payment service provider to accept donations and fundraisers.', 'ambassadorhub' ),
				'done'         => get_option( 'ambh_active_connector_psp', '' ) !== '',
				'url'          => esc_url( $settings_url . '&tab=psp' ),
				'action_label' => __( 'Go to PSP settings', 'ambassadorhub' ),
			),
			array(
				'title'        => __( 'Create your first fundraiser', 'ambassadorhub' ),
				'description'  => __( 'Set up a root fundraiser to start inviting ambassadors and collecting donations.', 'ambassadorhub' ),
				'done'         => (int) ( wp_count_posts( FundraisersModule::POST_TYPE )->publish ?? 0 ) > 0,
				'url'          => admin_url( 'post-new.php?post_type=' . FundraisersModule::POST_TYPE ),
				'action_label' => __( 'Create fundraiser', 'ambassadorhub' ),
			),
		);

		return (array) apply_filters( 'ambh_dashboard_setup_steps', $steps );
	}

	/**
	 * Output the donations chart section.
	 *
	 * Fetches the chart data and calls ChartRenderer to output the chart.
	 * Should only be called if there are completed donations (i.e. data to show).
	 * Encapsulated in its own method for clarity and separation of concerns.
	 * @return void
	 * @see get_chart_data() for how the data is retrieved and cached.
	 * @see ChartRenderer::render() for how the chart is rendered.
	 */
	private static function get_dashboard_chart(): void {

		$chart_data = self::get_chart_data();
		ChartRenderer::render(
			__( 'Donations', 'ambassadorhub' ),
			'ambh-donations-chart',
			array(
				'type'    => 'bar',
				'data'    => array(
					'labels'   => $chart_data['labels'],
					'datasets' => array(
						array(
							'type'        => 'bar',
							'label'       => __( 'Amount donated (€)', 'ambassadorhub' ),
							'data'        => $chart_data['amounts'],
							'borderWidth' => 1,
							'yAxisID'     => 'y',
						),
						array(
							'type'        => 'line',
							'label'       => __( 'Number of donors', 'ambassadorhub' ),
							'data'        => $chart_data['donors'],
							'borderWidth' => 2,
							'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 ),
						),
					),
				),
			)
		);
	}

	// -------------------------------------------------------------------------
	// KPIs
	// -------------------------------------------------------------------------

	/**
	 * Build KPI card data for the dashboard.
	 *
	 * @return array<int, array{icon: string, value: string, label: string, url: string}>
	 */
	private static function get_kpis(): array {
		$kpis = array();

		// All active fundraisers across all depths.
		$active_count = (int) ( new \WP_Query(
			array(
				'post_type'      => FundraisersModule::POST_TYPE,
				'post_status'    => 'publish',
				'posts_per_page' => -1,
				'fields'         => 'ids',
			)
		) )->found_posts;
		$kpis[]       = array(
			'icon'  => 'dashicons-megaphone',
			'value' => number_format_i18n( $active_count ),
			'label' => __( 'Active fundraisers', 'ambassadorhub' ),
			'url'   => admin_url( 'edit.php?post_type=' . FundraisersModule::POST_TYPE ),
		);

		// Total ambassadors.
		$user_counts      = count_users();
		$ambassador_count = (int) ( $user_counts['avail_roles'][ Roles::ROLE_AMBASSADOR ] ?? 0 );
		$kpis[]           = array(
			'icon'  => 'dashicons-groups',
			'value' => number_format_i18n( $ambassador_count ),
			'label' => __( 'Ambassadors', 'ambassadorhub' ),
			'url'   => admin_url( 'admin.php?page=ambassadorhub-ambassadors' ),
		);

		// Total donors.
		$kpis[] = array(
			'icon'  => 'dashicons-id',
			'value' => number_format_i18n( DonorsModule::count() ),
			'label' => __( 'Donors', 'ambassadorhub' ),
			'url'   => admin_url( 'admin.php?page=ambassadorhub-donors' ),
		);

		return (array) apply_filters( 'ambh_dashboard_kpis', $kpis );
	}

	// -------------------------------------------------------------------------
	// Chart data
	// -------------------------------------------------------------------------

	/**
	 * Get monthly donation amounts and donor counts for the past 12 months.
	 *
	 * Results are cached in a transient for 6 hours and invalidated automatically
	 * when a donation is created, updated, or deleted.
	 *
	 * @return array{labels: string[], amounts: float[], donors: int[]}
	 */
	private static function get_chart_data(): array {
		$cached = get_transient( self::CHART_CACHE_KEY );
		if ( is_array( $cached ) ) {
			return $cached;
		}

		global $wpdb;
		$table = esc_sql( DonationsModule::get_table_name() );

		$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 created_at >= %s
				GROUP BY month
				ORDER BY month ASC",
				'completed',
				gmdate( 'Y-m-01', strtotime( '-11 months' ) )
			)
		);

		$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;
			$donors[]  = $row_map[ $key ]['donors'] ?? 0;
		}

		$data = compact( 'labels', 'amounts', 'donors' );
		set_transient( self::CHART_CACHE_KEY, $data, 6 * HOUR_IN_SECONDS );

		return $data;
	}
}
