<?php
/**
 * DESCRIPTION: Base class for all Nemtly Booking Elementor widgets. Provides the shared
 * DESCRIPTION: event-picker control, published-event/term lookups, editor-mode detection,
 * DESCRIPTION: and the asset enqueue+localize helpers that mirror the equivalent blocks.
 *
 * @since   PBOOKING_SINCE
 * @package NemtlyBooking\Integrations\Elementor
 */

namespace NemtlyBooking\Integrations\Elementor;

use Elementor\Widget_Base;
use Elementor\Controls_Manager;

/**
 * Abstract Nemtly Elementor widget.
 *
 * Each concrete widget renders the *same* frontend markup as its Gutenberg block
 * counterpart (so existing CSS and frontend scripts drive it), and a native
 * server-rendered preview inside the Elementor editor.
 *
 * @since PBOOKING_SINCE
 */
abstract class Abstract_Widget extends Widget_Base {

	/**
	 * The widget category shown in the Elementor panel.
	 *
	 * @since PBOOKING_SINCE
	 *
	 * @return string[]
	 */
	public function get_categories() {
		return [ 'nemtly-booking' ];
	}

	/**
	 * Whether the widget is currently being rendered inside the Elementor editor.
	 *
	 * Used to branch render() between the native live-data preview (editor) and
	 * the real interactive markup (frontend / preview-changes / live site).
	 *
	 * @since PBOOKING_SINCE
	 *
	 * @return bool
	 */
	protected function is_editor_preview() {
		return did_action( 'elementor/loaded' )
			&& isset( \Elementor\Plugin::$instance->editor )
			&& \Elementor\Plugin::$instance->editor->is_edit_mode();
	}

	/**
	 * Verify an event exists, is the correct post type, and is published.
	 *
	 * @since PBOOKING_SINCE
	 *
	 * @param int $event_id Event post ID.
	 *
	 * @return bool
	 */
	protected function is_valid_event( $event_id ) {
		$event_id = absint( $event_id );

		if ( ! $event_id ) {
			return false;
		}

		$post = get_post( $event_id );

		return $post && 'nemtly_event' === $post->post_type && 'publish' === $post->post_status;
	}

	/**
	 * Build an ID => title map of published events for a SELECT2 control.
	 *
	 * @since PBOOKING_SINCE
	 *
	 * @return array<int,string>
	 */
	protected function get_event_options() {
		$event_ids = get_posts(
			[
				'post_type'        => 'nemtly_event',
				'post_status'      => 'publish',
				'numberposts'      => -1,
				'orderby'          => 'title',
				'order'            => 'ASC',
				'fields'           => 'ids',
				'suppress_filters' => false,
			]
		);

		$options = [];
		foreach ( $event_ids as $event_id ) {
			$options[ $event_id ] = get_the_title( $event_id );
		}

		return $options;
	}

	/**
	 * Build a term_id => name map for a taxonomy, for a SELECT2 control.
	 *
	 * @since PBOOKING_SINCE
	 *
	 * @param string $taxonomy Taxonomy slug.
	 *
	 * @return array<int,string>
	 */
	protected function get_term_options( $taxonomy ) {
		$terms = get_terms(
			[
				'taxonomy'   => $taxonomy,
				'hide_empty' => false,
			]
		);

		$options = [];
		if ( ! is_wp_error( $terms ) ) {
			foreach ( $terms as $term ) {
				$options[ $term->term_id ] = $term->name;
			}
		}

		return $options;
	}

	/**
	 * Add the shared "Event" SELECT2 control to the current section.
	 *
	 * @since PBOOKING_SINCE
	 *
	 * @return void
	 */
	protected function add_event_control() {
		$this->add_control(
			'event_id',
			[
				'label'       => __( 'Event', 'nemtly-booking' ),
				'type'        => Controls_Manager::SELECT2,
				'options'     => $this->get_event_options(),
				'label_block' => true,
				'description' => __( 'Choose the published event this widget targets.', 'nemtly-booking' ),
			]
		);
	}

	/**
	 * Render the "please select an event" notice used in the editor preview.
	 *
	 * @since PBOOKING_SINCE
	 *
	 * @return void
	 */
	protected function render_select_event_notice() {
		printf(
			'<div class="nemtly-elementor-preview nemtly-elementor-preview--notice"><p>%s</p></div>',
			esc_html__( 'Please select a published event in the widget settings.', 'nemtly-booking' )
		);
	}

	/**
	 * Enqueue the event-calendar script/style and localize its config.
	 *
	 * Mirrors Event_Calendar::enqueue_calendar_assets(). Guarded so multiple
	 * calendars on one page don't re-localize.
	 *
	 * @since PBOOKING_SINCE
	 *
	 * @param array $config Calendar config values mapped from widget settings.
	 *
	 * @return void
	 */
	protected function enqueue_calendar_assets( array $config ) {
		wp_enqueue_style(
			'nemtly-event-calendar-styles',
			NEMTLY_BOOKING_URL . 'assets/css/event-calendar.css',
			[],
			NEMTLY_BOOKING_VERSION
		);

		if ( wp_script_is( 'nemtly-event-calendar', 'enqueued' ) ) {
			return;
		}

		$asset_path = NEMTLY_BOOKING_PATH . 'assets/js/event-calendar.asset.php';
		$asset      = file_exists( $asset_path ) ? require $asset_path : [
			'dependencies' => [ 'wp-element', 'wp-api-fetch', 'wp-i18n' ],
			'version'      => NEMTLY_BOOKING_VERSION,
		];

		wp_enqueue_script(
			'nemtly-event-calendar',
			NEMTLY_BOOKING_URL . 'assets/js/event-calendar.js',
			$asset['dependencies'],
			$asset['version'],
			true
		);

		wp_localize_script(
			'nemtly-event-calendar',
			'nemtlyCalendar',
			self::calendar_localize_data( $config )
		);

		wp_add_inline_script(
			'nemtly-event-calendar',
			sprintf(
				'wp.apiFetch.use( wp.apiFetch.createNonceMiddleware( %s ) );',
				wp_json_encode( wp_create_nonce( 'wp_rest' ) )
			),
			'before'
		);

		wp_set_script_translations( 'nemtly-event-calendar', 'nemtly-booking' );
	}

	/**
	 * Build the `nemtlyCalendar` config array shared by the calendar widget and the
	 * Elementor editor preview. Per-instance display options arrive via data-* attributes;
	 * this provides the page-level config and localized strings.
	 *
	 * @since PBOOKING_SINCE
	 *
	 * @param array $config Optional overrides (defaultView, availableViews, firstDayOfWeek,
	 *                      eventsPerCell, showBookingBtn, showPastEvents, calendarHeight,
	 *                      calendarHeightPx).
	 *
	 * @return array
	 */
	public static function calendar_localize_data( array $config = [] ) {
		$config = wp_parse_args(
			$config,
			[
				'defaultView'      => 'month',
				'availableViews'   => [ 'month', 'week', 'day', 'list' ],
				'firstDayOfWeek'   => 0,
				'eventsPerCell'    => 3,
				'showBookingBtn'   => true,
				'showPastEvents'   => false,
				'calendarHeight'   => 'auto',
				'calendarHeightPx' => 600,
			]
		);

		return [
			'restUrl'          => rest_url( 'nemtly-booking/v1' ),
			'restNonce'        => wp_create_nonce( 'wp_rest' ),
			'defaultView'      => $config['defaultView'],
			'availableViews'   => $config['availableViews'],
			'firstDayOfWeek'   => (int) $config['firstDayOfWeek'],
			'eventsPerCell'    => (int) $config['eventsPerCell'],
			'timeFormat'       => 'site_default',
			'showEventTime'    => true,
			'showBookingBtn'   => (bool) $config['showBookingBtn'],
			'showPastEvents'   => (bool) $config['showPastEvents'],
			'colorBy'          => 'category',
			'categoryColors'   => [],
			'calendarHeight'   => $config['calendarHeight'],
			'calendarHeightPx' => (int) $config['calendarHeightPx'],
			'siteTimezone'     => wp_timezone_string(),
			'strings'          => [
				'loading'       => __( 'Loading events...', 'nemtly-booking' ),
				'noEvents'      => __( 'No events this period.', 'nemtly-booking' ),
				'error'         => __( 'Could not load events. Please try again.', 'nemtly-booking' ),
				'retry'         => __( 'Retry', 'nemtly-booking' ),
				'today'         => __( 'Today', 'nemtly-booking' ),
				'month'         => __( 'Month', 'nemtly-booking' ),
				'week'          => __( 'Week', 'nemtly-booking' ),
				'day'           => __( 'Day', 'nemtly-booking' ),
				'list'          => __( 'List', 'nemtly-booking' ),
				'viewDetails'   => __( 'View Details', 'nemtly-booking' ),
				'bookNow'       => __( 'Book Now', 'nemtly-booking' ),
				'allCategories' => __( 'All Categories', 'nemtly-booking' ),
				'allTags'       => __( 'All Tags', 'nemtly-booking' ),
				/* translators: %d: number of additional events not shown in the cell */
				'moreEvents'    => __( '+%d more', 'nemtly-booking' ),
				'noJs'          => __( 'Please enable JavaScript to view the event calendar.', 'nemtly-booking' ),
			],
		];
	}
}
