<?php

namespace SugarCalendarBookings\Admin;

use SugarCalendarBookings\Appointments\Admin\AppointmentDetailsPage;
use SugarCalendarBookings\Appointments\AppointmentModel;
use SugarCalendarBookings\Plugin;
use SugarCalendarBookings\Support\Bootable;
use SugarCalendarBookings\Support\Helpers\Date;
use SugarCalendarBookings\Support\Helpers\Time;
use SugarCalendarBookings\Payments\PaymentModel;
use SugarCalendarBookings\Payments\PaymentsHelpers;
use SugarCalendarBookings\Support\Helpers\Helpers;
use SugarCalendarBookings\Support\Helpers\WP;

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

/**
 * Dashboard Widget.
 *
 * @since 1.1.0
 */
class DashboardWidget implements Bootable {

	/**
	 * The meta key for the hide education meta.
	 *
	 * @since 1.1.0
	 *
	 * @var string
	 */
	const SAVE_WIDGET_META_KEY = 'sugar_calendar_bookings_hide_dashboard_recommended_plugin';

	/**
	 * Register hooks.
	 *
	 * @since 1.1.0
	 */
	public function hooks(): void {

		add_action( 'wp_dashboard_setup', [ $this, 'register_widget' ] );
		add_action( 'admin_enqueue_scripts', [ $this, 'enqueue_assets' ] );
	}

	/**
	 * Register the dashboard widget.
	 *
	 * @since 1.1.0
	 */
	public function register_widget(): void {

		// Only load on dashboard page.
		if ( ! $this->is_dashboard_page() ) {
			return;
		}

		global $wp_meta_boxes;

		$widget_key = 'sugar-calendar-bookings-dashboard-widget';

		wp_add_dashboard_widget(
			$widget_key,
			esc_html__( 'Sugar Calendar Bookings', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			[ $this, 'widget_content' ]
		);

		// Attempt to place the widget at the top.
		$normal_dashboard = $wp_meta_boxes['dashboard']['normal']['core'];
		$widget_instance  = [ $widget_key => $normal_dashboard[ $widget_key ] ];

		unset( $normal_dashboard[ $widget_key ] );

		$sorted_dashboard = array_merge( $widget_instance, $normal_dashboard );

		// phpcs:ignore WordPress.WP.GlobalVariablesOverride.Prohibited
		$wp_meta_boxes['dashboard']['normal']['core'] = $sorted_dashboard;
	}

	/**
	 * Enqueue assets.
	 *
	 * @since 1.1.0
	 */
	public function enqueue_assets(): void {

		// Only load on dashboard page.
		if ( ! $this->is_dashboard_page() ) {
			return;
		}

		$assets = Plugin::get( Assets::class );

		if ( $assets->is_dev() ) {
			$assets->enqueue_dev_runtime();
		}

		// Register React JSX runtime for React components.
		$this->register_react_jsx_runtime();

		$this->enqueue_common_assets( $assets );

		$this->enqueue_dashboard_widget_assets( $assets );

		// Required for Service feature image (when creating service from appointment form).
		wp_enqueue_media();

		// Required for WYSIWYG editor (when creating service from appointment form).
		wp_enqueue_editor();
	}

	/**
	 * Register the React JSX runtime if not available in older WordPress versions.
	 *
	 * @since 1.1.0
	 */
	private function register_react_jsx_runtime(): void {

		if ( ! wp_script_is( 'react-jsx-runtime', 'registered' ) ) {
			wp_register_script(
				'react-jsx-runtime',
				SCBOOKINGS_PLUGIN_URL . 'assets/lib/react-jsx-runtime.js',
				[ 'react' ],
				'18.3.1',
				true
			);
		}
	}

	/**
	 * Enqueue common assets.
	 *
	 * @since 1.1.0
	 *
	 * @param Assets $assets The assets instance.
	 */
	private function enqueue_common_assets( Assets $assets ): void {

		// Enqueue common admin assets (includes general admin styles).
		$common_manifest = $assets->get_asset_manifest( 'admin/common' );

		if ( $common_manifest !== false ) {
			wp_enqueue_script(
				'sugar-calendar-bookings-admin-common',
				$assets->get_src( 'admin/common.js' ),
				$common_manifest['dependencies'],
				$assets->is_dev() ? $common_manifest['version'] : SCBOOKINGS_PLUGIN_VERSION,
				true
			);

			wp_enqueue_style(
				'sugar-calendar-bookings-admin-common',
				$assets->get_src( 'admin/common.css' ),
				[],
				$assets->is_dev() ? $common_manifest['version'] : SCBOOKINGS_PLUGIN_VERSION
			);
		}

		// Enqueue appointments list assets (includes modal and badges styles used in AppointmentForm).
		$appointments_list_manifest = $assets->get_asset_manifest( 'admin/pages/appointments-list' );

		if ( $appointments_list_manifest !== false ) {
			wp_enqueue_style(
				'sugar-calendar-bookings-admin-pages-appointments-list',
				$assets->get_src( 'admin/pages/appointments-list.css' ),
				[],
				$assets->is_dev() ? $appointments_list_manifest['version'] : SCBOOKINGS_PLUGIN_VERSION
			);
		}
	}

	/**
	 * Enqueue dashboard widget assets.
	 *
	 * @since 1.1.0
	 *
	 * @param Assets $assets The assets instance.
	 */
	private function enqueue_dashboard_widget_assets( Assets $assets ): void {

		// Enqueue dashboard widget specific assets.
		$manifest = $assets->get_asset_manifest( 'admin/dashboard-widget' );

		if ( $manifest !== false ) {
			wp_enqueue_style(
				'sugar-calendar-bookings-admin-dashboard-widget',
				$assets->get_src( 'admin/dashboard-widget.css' ),
				[],
				$assets->is_dev() ? $manifest['version'] : SCBOOKINGS_PLUGIN_VERSION
			);

			wp_enqueue_script(
				'sugar-calendar-bookings-admin-dashboard-widget',
				$assets->get_src( 'admin/dashboard-widget.js' ),
				$manifest['dependencies'],
				$assets->is_dev() ? $manifest['version'] : SCBOOKINGS_PLUGIN_VERSION,
				true
			);

			wp_set_script_translations(
				'sugar-calendar-bookings-admin-dashboard-widget',
				'sugar-calendar-bookings-scheduling-appointments-lite',
				SCBOOKINGS_PLUGIN_PATH . 'assets/languages'
			);

			wp_localize_script(
				'sugar-calendar-bookings-admin-dashboard-widget',
				'sugar_calendar_bookings_admin',
				[
					'ajax_url'  => WP::ajax_url(),
					'build_url' => SCBOOKINGS_PLUGIN_URL . 'assets/dist/',
					'is_pro'    => sugar_calendar_bookings()->is_pro(),
				]
			);
		}
	}

	/**
	 * Widget content.
	 *
	 * @since 1.1.0
	 */
	public function widget_content(): void {

		?>
		<div class="sugar-calendar-bookings-dash-widget">

			<div class="sugar-calendar-bookings-dash-widget-content">

				<?php $this->render_widget_header(); ?>

				<?php $this->render_upcoming_appointment_list(); ?>
			</div>

			<?php $this->render_education(); ?>

			<div id="sugar-calendar-bookings-sidebar"></div>
		</div>
		<?php
	}

	/**
	 * Render the widget header.
	 *
	 * @since 1.1.0
	 */
	public function render_widget_header(): void {

		?>
		<div class="sugar-calendar-bookings-dash-widget-block-title sugar-calendar-bookings-dash-widget-block">
			<h3>
				<?php esc_html_e( 'Upcoming Appointments', 'sugar-calendar-bookings-scheduling-appointments-lite' ); ?>
			</h3>

			<a href="#" class="button button-small button-secondary sugar-calendar-bookings-btn-new-item">
				<span><?php esc_html_e( 'Create Appointment', 'sugar-calendar-bookings-scheduling-appointments-lite' ); ?></span>
			</a>
		</div>
		<?php
	}

	/**
	 * Render the upcoming appointment list.
	 *
	 * @since 1.1.0
	 */
	public function render_upcoming_appointment_list(): void {

		$widget_appointments = $this->get_dashboard_widget_appointments();

		// If no appointments, render the empty state.
		if ( empty( $widget_appointments ) ) {

			$this->render_upcoming_appointment_list_empty();

			return;
		}

		?>
		<div class="sugar-calendar-bookings-dash-widget-block-appointment-list sugar-calendar-bookings-dash-widget-block">
			<?php
				foreach ( $widget_appointments as $widget_appointment ) {

					$this->render_upcoming_appointment_list_item( $widget_appointment );
				}
			?>
		</div>
		<?php
	}

	/**
	 * Render the upcoming appointment list empty state.
	 *
	 * @since 1.1.0
	 */
	public function render_upcoming_appointment_list_empty(): void {

		?>
		<div class="sugar-calendar-bookings-dash-widget-block-appointment-list-empty sugar-calendar-bookings-dash-widget-block">
			<div class="sugar-calendar-bookings-dash-widget-icon-container">
				<img src="<?php echo esc_url( SCBOOKINGS_PLUGIN_URL . 'assets/images/icons/calendar-check.svg' ); ?>" alt="<?php esc_attr_e( 'Calendar Icon', 'sugar-calendar-bookings-scheduling-appointments-lite' ); ?>" width="80" height="80">
			</div>
			<h3>
				<?php esc_html_e( 'No Upcoming Appointments!', 'sugar-calendar-bookings-scheduling-appointments-lite' ); ?>
			</h3>
		</div>
		<?php
	}

	/**
	 * Render the upcoming appointment list item.
	 *
	 * @since 1.1.0
	 *
	 * @param array $widget_appointment The widget appointment.
	 */
	public function render_upcoming_appointment_list_item( $widget_appointment ): void {

		// Get payment status class for styling.
		$payment_status_class = empty( $widget_appointment['payment_slug'] )
			? ''
			: 'sugar-calendar-bookings-dash-widget-payment-' . $widget_appointment['payment_slug'];

		ob_start();
		?>
		<div class="sugar-calendar-bookings-dash-widget-block-appointment-list-item <?php echo esc_attr( $payment_status_class ); ?>">

			<div class="sugar-calendar-bookings-dash-widget-appointment-main">

				<div class="sugar-calendar-bookings-dash-widget-appointment-service">
					<span
						class="sugar-calendar-bookings-dash-widget-service-color"
						style="background-color: <?php echo esc_attr( $widget_appointment['service_color'] ); ?>"
					></span>
					<a href="<?php echo esc_url( $widget_appointment['details_url'] ); ?>" class="sugar-calendar-bookings-dash-widget-service-title">
						<?php echo esc_html( $widget_appointment['service_name'] . ' - {' . $widget_appointment['customer_name'] . '}' ); ?>
					</a>
				</div>

				<div class="sugar-calendar-bookings-dash-widget-appointment-details">
					<span class="sugar-calendar-bookings-dash-widget-detail-date">
						<?php echo esc_html( $widget_appointment['start_date'] ); ?>
					</span>
					<span class="sugar-calendar-bookings-dash-widget-detail-separator"></span>
					<span class="sugar-calendar-bookings-dash-widget-detail-time">
						<?php echo esc_html( $widget_appointment['start_time'] ); ?>
					</span>
					<span class="sugar-calendar-bookings-dash-widget-detail-separator"></span>
					<span class="sugar-calendar-bookings-dash-widget-detail-duration">
						<?php echo esc_html( $widget_appointment['duration'] ); ?>
					</span>
					<span class="sugar-calendar-bookings-dash-widget-detail-separator"></span>
					<span class="sugar-calendar-bookings-dash-widget-detail-payment">
						<?php
						echo wp_sprintf(
							/* translators: %s - gateway name suffix (e.g., " (On Site)" or empty string). */
							esc_html__( 'Payment%s: ', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
							empty( $widget_appointment['gateway_name'] )
								? ''
								: ' (' . esc_html( $widget_appointment['gateway_name'] ) . ')'
						);
						?>
						<span class="sugar-calendar-bookings-dash-widget-payment-status">
							<?php echo esc_html( $widget_appointment['payment_status'] ); ?>
						</span>
					</span>
				</div>

			</div>

			<div class="sugar-calendar-bookings-dash-widget-appointment-actions">
				<a
					href="<?php echo esc_url( $widget_appointment['details_url'] ); ?>"
					class="sugar-calendar-bookings-dash-widget-action-button sugar-calendar-bookings-dash-widget-action-view"
					title="<?php esc_attr_e( 'View Appointment', 'sugar-calendar-bookings-scheduling-appointments-lite' ); ?>"
				>
				</a>
				<a
					href="<?php echo esc_url( $widget_appointment['edit_url'] ); ?>"
					class="sugar-calendar-bookings-dash-widget-action-button sugar-calendar-bookings-dash-widget-action-edit"
					title="<?php esc_attr_e( 'Edit Appointment', 'sugar-calendar-bookings-scheduling-appointments-lite' ); ?>"
					data-appointment-id="<?php echo esc_attr( $widget_appointment['id'] ); ?>"
				>
				</a>
			</div>

		</div>
		<?php
		/**
		 * Filter the dashboard widget item.
		 *
		 * @since 1.1.0
		 *
		 * @param string $dashboard_widget_item The dashboard widget item.
		 * @param array  $widget_appointment    The widget appointment.
		 */
		$dashboard_widget_item = apply_filters(
			'sugar_calendar_bookings_admin_dashboard_widget_appointment_item',
			ob_get_clean(),
			$widget_appointment
		);

		echo wp_kses_post( $dashboard_widget_item );
	}

	/**
	 * Get the dashboard widget appointments.
	 *
	 * @since 1.1.0
	 *
	 * @return array
	 */
	public function get_dashboard_widget_appointments(): array {

		$now = Date::create();

		/**
		 * Filter the time range for upcoming appointments in the dashboard widget.
		 *
		 * @since 1.1.0
		 *
		 * @param string $upcoming_string The time string to modify the current date (e.g., '+2 weeks', '+1 month', '+30 days').
		 */
		$upcoming_string = apply_filters(
			'sugar_calendar_bookings_admin_dashboard_widget_upcoming_appointments_range',
			'+2 weeks'
		);

		$upcoming_time = $now->modify( $upcoming_string );

		$now_utc = Date::to_utc( $now )->format( Date::DB_DATETIME_FORMAT );

		$upcoming_utc = Date::to_utc( $upcoming_time )->format( Date::DB_DATETIME_FORMAT );

		/**
		 * Filter the upcoming appointments status for the dashboard widget.
		 *
		 * This will be automatically trimmed to "=" in the query if singular.
		 *
		 * @since 1.1.0
		 *
		 * @param string $status The status to filter the appointments by.
		 */
		$status = apply_filters(
			'sugar_calendar_bookings_admin_dashboard_widget_upcoming_appointments_status',
			[
				AppointmentModel::STATUS_APPROVED,
			]
		);

		/**
		 * Filter the upcoming appointments query for the dashboard widget.
		 *
		 * @since 1.1.0
		 *
		 * @param QueryBuilder $query The query builder instance.
		 */
		$appointments = apply_filters(
			'sugar_calendar_bookings_admin_dashboard_widget_upcoming_appointments_query',
			AppointmentModel::query()
			->with(
				[
					'service'  => fn( $q ) => $q->select( [ 'id', 'name', 'color' ] ),
					'customer' => fn( $q ) => $q->select( [ 'id', 'name' ] ),
					'location' => fn( $q ) => $q->select( [ 'id', 'name' ] ),
					'payments' => fn( $q ) => $q->select( [ 'id', 'status', 'gateway' ] ),
				]
			)
			->join( 'payment_items', 'appointments.id', '=', 'payment_items.item_id', 'INNER' )
			->join( 'payments', 'payment_items.payment_id', '=', 'payments.id', 'INNER' )
			->where( 'appointments.status', 'IN', $status, '%s' )
			->where( 'appointments.start_at', '>=', $now_utc, '%s' )
			->where( 'appointments.start_at', '<=', $upcoming_utc, '%s' )
			->where( 'payments.status', 'IN', [ 'pending', 'completed' ], '%s' )
			->group_by( [ 'appointments.id' ] )
			->order_by( 'appointments.start_at', 'ASC' )
			->limit( 5 )
			->get()
		);

		if ( empty( $appointments ) ) {
			return [];
		}

		$widget_appointments = [];

		foreach ( $appointments as $appointment ) {

			$appointment_item = $this->get_dashboard_widget_appointment( $appointment );

			if ( empty( $appointment_item ) ) {
				continue;
			}

			$widget_appointments[] = $appointment_item;
		}

		return $widget_appointments;
	}

	/**
	 * Get the widget appointment data.
	 *
	 * @since 1.1.0
	 *
	 * @param AppointmentModel $appointment The appointment.
	 *
	 * @return array The appointment data.
	 */
	public function get_dashboard_widget_appointment( $appointment ): array {

		// Initialize appointment data with default payment values.
		$appointment_data = [
			'id'             => $appointment->id,
			'service_name'   => $appointment->service ? $appointment->service->name : '',
			'service_color'  => $appointment->service ? $appointment->service->color : '#8659C2',
			'customer_name'  => $appointment->customer ? $appointment->customer->name : '',
			'start_date'     => Date::format_display_date( $appointment->start_at, 'M j, Y' ),
			'start_time'     => Date::format_display_date( $appointment->start_at, 'g:i A' ),
			'duration'       => Time::human_readable_duration( $appointment->get_duration() ),
			'payment_status' => esc_html__( 'N/A', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
			'payment_slug'   => '',
			'gateway_name'   => '',
			'details_url'    => AppointmentDetailsPage::get_url( $appointment->id ),
			'edit_url'       => '#', // JavaScript sidebar trigger.
		];

		$payment = PaymentsHelpers::get_payment( $appointment );

		// Update payment values if PaymentModel exists.
		if ( $payment instanceof PaymentModel ) {
			$appointment_data['payment_status'] = $payment->get_status_label();
			$appointment_data['payment_slug']   = $payment->status;
			$appointment_data['gateway_name']   = PaymentsHelpers::get_payment_gateway_display_name( $payment );
		}

		/**
		 * Filter the appointment data for the dashboard widget.
		 *
		 * @since 1.1.0
		 *
		 * @param array            $appointment_data The appointment data.
		 * @param AppointmentModel $appointment      The appointment object.
		 */
		return apply_filters( 'sugar_calendar_bookings_admin_dashboard_widget_appointment_data', $appointment_data, $appointment );
	}

	/**
	 * Render the education block.
	 *
	 * @since 1.1.0
	 */
	public function render_education(): void {

		// If Pro, run hooks.
		$pro = sugar_calendar_bookings()->is_pro();

		if ( $pro ) {

			/**
			 * Fires when rendering the education block in the dashboard widget.
			 *
			 * @since 1.1.0
			 *
			 * @param DashboardWidget $this The DashboardWidget instance.
			 */
			do_action( 'sugar_calendar_bookings_admin_dashboard_widget_pro_education', $this );

			return;
		}

		// If the user has hidden the education block, don't render it.
		if ( get_user_meta( get_current_user_id(), self::SAVE_WIDGET_META_KEY, true ) ) {
			return;
		}

		// If we're here, render the Lite education block.
		$upgrade_link = wp_sprintf(
			'<a href="%s" target="_blank">%s</a>',
			Helpers::get_utm_url(
				'https://sugarcalendar.com/pricing/bookings/',
				[
					'medium' => 'dashboard-widget',
				]
			),
			'<strong>' . __( 'Get Pro', 'sugar-calendar-bookings-scheduling-appointments-lite' ) . '</strong>'
		);
		?>
		<div class="sugar-calendar-bookings-dash-widget-education-block sugar-calendar-bookings-dash-widget-block">

			<span class="sugar-calendar-bookings-dash-widget-recommended-plugin">
				<?php
				echo wp_kses_post(
					sprintf(
						/* translators: %1$s - upgrade link with "Get Pro" text. */
						__( 'Upgrade to <strong>Sugar Calendar Pro</strong> and get access to powerful features like Booking Forms, Custom Emails, Importing .ics files, and much more! %1$s', 'sugar-calendar-bookings-scheduling-appointments-lite' ),
						$upgrade_link
					)
				);
				?>
			</span>

		<button
			type="button"
			class="sugar-calendar-bookings-dash-widget-dismiss-icon sugar-calendar-bookings-widget-ajax-action"
			title="<?php esc_html_e( 'Dismiss', 'sugar-calendar-bookings-scheduling-appointments-lite' ); ?>"
			data-meta-name="<?php echo esc_attr( self::SAVE_WIDGET_META_KEY ); ?>"
		></button>
		</div>
		<?php
	}

	/**
	 * Check if current page is dashboard.
	 *
	 * @since 1.1.0
	 *
	 * @return bool
	 */
	private function is_dashboard_page(): bool {

		$screen = get_current_screen();

		return ! empty( $screen->id ) && $screen->id === 'dashboard';
	}
}
