<?php
/**
 * Registers Radius Booking preset fields in the Classified Listing Form Builder.
 *
 * @package RadiusTheme\RadiusBooking\Integrations\ClassifiedListing
 */

namespace RadiusTheme\RadiusBooking\Integrations\ClassifiedListing;

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

use RadiusTheme\RadiusBooking\Helpers\SettingsHelper;
use RadiusTheme\RadiusBooking\Models\Category;

/**
 * Class ListingFormBuilder
 *
 * Adds the "Radius Booking" preset field to the Classified Listing Form Builder.
 * Service Name and Staff Email are grouped within this single element:
 * - Service Name: editor-only setting (admin configures per form).
 * - Staff Email: rendered on the frontend form via JS when staff mode is active.
 */
class ListingFormBuilder {

	/**
	 * Register hooks.
	 */
	public function __construct() {
		add_filter( 'rtcl_fb_fields', array( $this, 'registerPresetFields' ) );

		// Patch field defaults BEFORE React loads (via localize filter).
		add_filter( 'rtcl_localize_fb_admin_params', array( $this, 'patchFieldDefaults' ) );

		// Inject editor settings via inline JS AFTER CL's footer scripts load.
		add_action( 'admin_print_footer_scripts', array( $this, 'injectEditorSettingsViaJS' ), 99 );

		// Single Layout: register "Booking Form" element.
		add_filter( 'rtcl/fb/single_layout/fields', array( $this, 'registerSingleLayoutFields' ) );

		// Redirect CL template loading to our plugin for the rtrb_booking element.
		add_filter( 'rtcl_locate_template', array( $this, 'overrideTemplate' ), 10, 2 );
	}

	/**
	 * Register Radius Booking preset fields.
	 *
	 * @param array $fields Existing form builder fields.
	 *
	 * @return array Modified fields.
	 */
	public function registerPresetFields( $fields ) {
		// Enable Booking toggle — the single "Radius Booking" element.
		// Service name is stored as a field property (rtrb_service_name),
		// configured via the editor sidebar. Staff email is injected on the
		// frontend by JavaScript when staff mode is active.
		$fields['rtrb_booking_enabled'] = array(
			'element'            => 'rtrb_booking_enabled',
			'preset'             => 1,
			'name'               => '_rtrb_booking_enabled',
			'default_value'      => '',
			'container_class'    => '',
			'label'              => __( 'Enable Booking', 'radius-booking' ),
			'label_placement'    => 'left',
			'help_message'       => __( 'Enable booking for this listing', 'radius-booking' ),
			'logics'             => '',
			'rtrb_mapping_mode'         => 'use_global',
			'rtrb_auto_create_employee' => 'use_global',
			'rtrb_sync_price'           => 'use_global',
			'rtrb_sync_description'     => 'use_global',
			'rtrb_default_duration'     => 0,
			'rtrb_service_name'         => __( 'Consultation', 'radius-booking' ),
			// Off by default — admin must explicitly opt in via the editor toggle.
			// Keeping this in sync with patchFieldDefaults() and the JS defaults
			// in injectEditorSettingsViaJS(); a stray `true` here was leaking
			// into freshly-dragged fields and forcing the frontend Staff Email
			// input to render even when the toggle was visibly off.
			'rtrb_staff_email_enabled'  => false,
			'validation'                => array(
				'required' => array(
					'value'   => false,
					'message' => __( 'This field is required', 'radius-booking' ),
				),
			),
			'editor'             => array(
				'title'      => __( 'Radius Booking', 'radius-booking' ),
				'icon_class' => 'rtcl-icon-toggle-on',
				'template'   => 'switch',
			),
		);

		return $fields;
	}

	/**
	 * Register custom editor settings fields for the Radius Booking element.
	 *
	 * Adds "Service Name" as a text input in the form builder editor sidebar.
	 *
	 * @param array $settings Existing editor settings fields.
	 *
	 * @return array Modified settings.
	 */
	public function registerCustomEditorSettingsFields( $settings ) {
		$settings['rtrb_service_name'] = array(
			'template'  => 'inputText',
			'label'     => __( 'Service Name', 'radius-booking' ),
			'help_text' => __( 'Service name used when creating the booking service in staff mode. Each form can have its own service name (e.g. "Doctor Consultation", "Legal Consultation").', 'radius-booking' ),
		);

		return $settings;
	}

	/**
	 * Register editor settings placement for the booking fields.
	 *
	 * @param array $placement Existing placement definitions.
	 *
	 * @return array Modified placement.
	 */
	public function registerEditorSettings( $placement ) {
		$placement['rtrb_booking_enabled'] = array(
			'general' => array(
				'label',
				'label_placement',
				'rtrb_service_name',
			),
			'advance' => array(
				'container_class',
				'help_message',
				'admin_use_only',
				'logics',
			),
		);

		return $placement;
	}

	/**
	 * Patch field defaults and editor settings into the localized data BEFORE React loads.
	 *
	 * @param array $params The rtclFB localized params.
	 *
	 * @return array Modified params.
	 */
	public function patchFieldDefaults( $params ) {
		$defaults = array(
			'rtrb_mapping_mode'         => 'use_global',
			'rtrb_service_name'         => __( 'Consultation', 'radius-booking' ),
			'rtrb_staff_email_enabled'  => false,
			'rtrb_auto_create_employee' => 'use_global',
			'rtrb_sync_price'           => 'use_global',
			'rtrb_sync_description'     => 'use_global',
			'rtrb_default_duration'     => 0,
		);

		// Patch the preset field definition (used when dragging a new element).
		if ( isset( $params['fields']['rtrb_booking_enabled'] ) ) {
			foreach ( $defaults as $key => $val ) {
				if ( ! isset( $params['fields']['rtrb_booking_enabled'][ $key ] ) ) {
					$params['fields']['rtrb_booking_enabled'][ $key ] = $val;
				}
			}
		}

		// Patch already-placed fields in existing forms.
		if ( ! empty( $params['forms'] ) && is_array( $params['forms'] ) ) {
			foreach ( $params['forms'] as &$form ) {
				if ( empty( $form->fields ) && empty( $form['fields'] ) ) {
					continue;
				}
				$fields = is_object( $form ) ? (array) $form->fields : ( $form['fields'] ?? array() );
				foreach ( $fields as $uuid => &$field ) {
					$field_arr = (array) $field;
					if ( ( $field_arr['name'] ?? '' ) === '_rtrb_booking_enabled' || ( $field_arr['elementId'] ?? '' ) === 'rtrb_booking_enabled' ) {
						foreach ( $defaults as $key => $val ) {
							if ( ! isset( $field_arr[ $key ] ) ) {
								if ( is_object( $field ) ) {
									$field->{$key} = $val;
								} else {
									$field[ $key ] = $val;
								}
							}
						}
					}
				}
				unset( $field );
				if ( is_object( $form ) ) {
					$form->fields = (object) $fields;
				} else {
					$form['fields'] = $fields;
				}
			}
			unset( $form );
		}

		return $params;
	}

	/**
	 * Inject all per-form editor settings via inline JS in the admin footer.
	 *
	 * This is the SINGLE source of truth for Radius Booking editor settings.
	 * Runs AFTER CL's scripts load, directly patches rtclFB so React reads them.
	 */
	public function injectEditorSettingsViaJS() {
		$screen = get_current_screen();
		if ( ! $screen || false === strpos( $screen->id, 'rtcl-fb' ) ) {
			return;
		}

		$l = array(
			'mapping_mode'  => __( 'Mapping Mode', 'radius-booking' ),
			'mapping_help'  => __( 'How listings map to booking entities. Leave empty to use global setting.', 'radius-booking' ),
			'use_global'    => __( 'Use Global Setting', 'radius-booking' ),
			'service_mode'  => __( 'Listing as Service', 'radius-booking' ),
			'staff_mode'    => __( 'Listing as Staff', 'radius-booking' ),
			'service_name'  => __( 'Service Name', 'radius-booking' ),
			'service_help'  => __( 'The booking service name for this directory/form.', 'radius-booking' ),
			'staff_email'   => __( 'Staff Email Field', 'radius-booking' ),
			'staff_email_h' => __( 'Show a Staff Email input on the listing form.', 'radius-booking' ),
//			'auto_emp'      => __( 'Auto-create employee from listing owner', 'radius-booking' ),
//			'auto_emp_h'    => __( 'Auto-create employee from listing owner (service mode).', 'radius-booking' ),
			'sync_price'    => __( 'Sync Price', 'radius-booking' ),
			'sync_price_h'  => __( 'Sync listing price to the booking service/staff.', 'radius-booking' ),
			'sync_desc'     => __( 'Sync Description', 'radius-booking' ),
			'sync_desc_h'   => __( 'Sync listing description to the service (service mode).', 'radius-booking' ),
//			'duration'      => __( 'Default Duration (min)', 'radius-booking' ),
//			'duration_h'    => __( 'Default appointment duration in minutes. 0 = use global.', 'radius-booking' ),
			'yes'           => __( 'Yes', 'radius-booking' ),
			'no'            => __( 'No', 'radius-booking' ),
		);
		?>
		<script id="rtrb-cl-fb-settings">
		(function(){
			if (typeof rtclFB === 'undefined' || !rtclFB.editor) return;
			var s = rtclFB.editor.settingsFields;
			if (!s) return;
			var g = '<?php echo esc_js( $l['use_global'] ); ?>';
			// 'use_global' is a sentinel value (not empty string) so the select renders
			// the option correctly when reloaded — empty-string values were dropping out.
			var yn = [{value:'use_global',label:g},{value:'1',label:'<?php echo esc_js( $l['yes'] ); ?>'},{value:'0',label:'<?php echo esc_js( $l['no'] ); ?>'}];

			s.rtrb_mapping_mode = {template:'radio',label:'<?php echo esc_js( $l['mapping_mode'] ); ?>',help_text:'<?php echo esc_js( $l['mapping_help'] ); ?>',default:'use_global',options:[{value:'use_global',label:g},{value:'service',label:'<?php echo esc_js( $l['service_mode'] ); ?>'},{value:'staff',label:'<?php echo esc_js( $l['staff_mode'] ); ?>'}]};
			s.rtrb_service_name = {template:'inputText',label:'<?php echo esc_js( $l['service_name'] ); ?>',help_text:'<?php echo esc_js( $l['service_help'] ); ?>',dependency:{depends_on:'rtrb_mapping_mode',value:'staff',operator:'=='}};
			s.rtrb_staff_email_enabled = {template:'switch',label:'<?php echo esc_js( $l['staff_email'] ); ?>',help_text:'<?php echo esc_js( $l['staff_email_h'] ); ?>',dependency:{depends_on:'rtrb_mapping_mode',value:'staff',operator:'=='}};
			//s.rtrb_auto_create_employee = {template:'radio',label:'<?php //echo $l['auto_emp']; ?>//',help_text:'<?php //echo $l['auto_emp_h']; ?>//',default:'use_global',options:yn,dependency:{depends_on:'rtrb_mapping_mode',value:'service',operator:'=='}};
			s.rtrb_sync_price = {template:'radio',label:'<?php echo esc_js( $l['sync_price'] ); ?>',help_text:'<?php echo esc_js( $l['sync_price_h'] ); ?>',default:'use_global',options:yn};
			s.rtrb_sync_description = {template:'radio',label:'<?php echo esc_js( $l['sync_desc'] ); ?>',help_text:'<?php echo esc_js( $l['sync_desc_h'] ); ?>',default:'use_global',options:yn,dependency:{depends_on:'rtrb_mapping_mode',value:'service',operator:'=='}};
			//s.rtrb_default_duration = {template:'inputNumber',label:'<?php //echo $l['duration']; ?>//',help_text:'<?php //echo $l['duration_h']; ?>//',default:0};

			if (rtclFB.editor.settingsPlacement) {
				rtclFB.editor.settingsPlacement.rtrb_booking_enabled = {
					general:['label','label_placement','rtrb_mapping_mode','rtrb_service_name','rtrb_staff_email_enabled','rtrb_auto_create_employee','rtrb_sync_price','rtrb_sync_description','rtrb_default_duration'],
					advance:['container_class','help_message','admin_use_only','logics']
				};
			}

			// Set default values on the preset field definition so newly dragged elements get them.
			if (rtclFB.fields && rtclFB.fields.rtrb_booking_enabled) {
				var f = rtclFB.fields.rtrb_booking_enabled;
				// Treat empty string as legacy 'use_global' so older saved data still
				// renders the "Use Global Setting" option correctly.
				if (f.rtrb_mapping_mode === undefined || f.rtrb_mapping_mode === '') f.rtrb_mapping_mode = 'use_global';
				if (f.rtrb_service_name === undefined) f.rtrb_service_name = '<?php echo esc_js( __( 'Consultation', 'radius-booking' ) ); ?>';
				if (f.rtrb_staff_email_enabled === undefined) f.rtrb_staff_email_enabled = false;
				if (f.rtrb_auto_create_employee === undefined || f.rtrb_auto_create_employee === '') f.rtrb_auto_create_employee = 'use_global';
				if (f.rtrb_sync_price === undefined || f.rtrb_sync_price === '') f.rtrb_sync_price = 'use_global';
				if (f.rtrb_sync_description === undefined || f.rtrb_sync_description === '') f.rtrb_sync_description = 'use_global';
				if (f.rtrb_default_duration === undefined) f.rtrb_default_duration = 0;
			}

			// Also patch any already-placed fields in existing forms.
			if (rtclFB.forms) {
				rtclFB.forms.forEach(function(form) {
					if (!form.fields) return;
					Object.keys(form.fields).forEach(function(key) {
						var ff = form.fields[key];
						if (ff.name === '_rtrb_booking_enabled' || ff.elementId === 'rtrb_booking_enabled') {
							if (ff.rtrb_mapping_mode === undefined || ff.rtrb_mapping_mode === '') ff.rtrb_mapping_mode = 'use_global';
							if (ff.rtrb_service_name === undefined) ff.rtrb_service_name = '<?php echo esc_js( __( 'Consultation', 'radius-booking' ) ); ?>';
							if (ff.rtrb_staff_email_enabled === undefined) ff.rtrb_staff_email_enabled = false;
							if (ff.rtrb_auto_create_employee === undefined || ff.rtrb_auto_create_employee === '') ff.rtrb_auto_create_employee = 'use_global';
							if (ff.rtrb_sync_price === undefined || ff.rtrb_sync_price === '') ff.rtrb_sync_price = 'use_global';
							if (ff.rtrb_sync_description === undefined || ff.rtrb_sync_description === '') ff.rtrb_sync_description = 'use_global';
							if (ff.rtrb_default_duration === undefined) ff.rtrb_default_duration = 0;
						}
					});
				});
			}
		})();
		</script>
		<?php
	}

	/**
	 * Register the "Booking Form" element in the Single Layout builder.
	 *
	 * @param array $fields Existing single layout elements.
	 *
	 * @return array Modified fields.
	 */
	public function registerSingleLayoutFields( $fields ) {
		$fields['rtrb_booking'] = array(
			'element' => 'rtrb_booking',
			'text'    => __( 'Book Now', 'radius-booking' ),
			'icon'    => array(
				'type'  => 'class',
				'class' => 'rtcl-icon-calendar',
			),
			'editor'  => array(
				'title'      => __( 'Radius Booking Form', 'radius-booking' ),
				'icon_class' => 'rtcl-icon-calendar',
				'template'   => 'action_button',
			),
		);

		return $fields;
	}

	/**
	 * Override template path for our single layout element.
	 *
	 * Hooked to 'rtcl_locate_template' which fires inside locate_template()
	 * before the file_exists check in get_template(). At this point
	 * $template_name already has '.php' appended by locate_template().
	 *
	 * @param string $template      The resolved template path from CL.
	 * @param string $template_name The template name with .php extension.
	 *
	 * @return string Modified template path.
	 */
	public function overrideTemplate( $template, $template_name ) {
		if ( 'single-layout/elements/rtrb-booking.php' === $template_name ) {
			$our_template = RADIUS_BOOKING_DIR . '/templates/single-layout/elements/rtrb-booking.php';
			if ( file_exists( $our_template ) ) {
				return $our_template;
			}
		}

		return $template;
	}

	/**
	 * Build options array for the booking category select field.
	 *
	 * @return array Options in the format expected by the form builder select element.
	 */
	private static function getBookingCategoryOptions() {
		$options = array();

		try {
			$categories = Category::all();
			if ( $categories ) {
				foreach ( $categories as $cat ) {
					$options[] = array(
						'label' => $cat->name,
						'value' => (string) $cat->id,
					);
				}
			}
		} catch ( \Exception $e ) {
			// Categories table may not exist yet.
			return $options;
		}

		return $options;
	}

	/**
	 * Static cache for effective settings.
	 *
	 * @var array
	 */
	private static $effective_settings_cache = array();

	/**
	 * Get effective CL integration settings for a listing, merging per-form
	 * overrides with global settings. Per-form values take precedence when set.
	 *
	 * Returns the same array shape as global classifiedListing settings,
	 * so callers can use it as a drop-in replacement.
	 *
	 * @param int $post_id The listing post ID.
	 *
	 * @return array Merged settings.
	 */
	public static function getEffectiveSettings( int $post_id ): array {
		if ( isset( self::$effective_settings_cache[ $post_id ] ) ) {
			return self::$effective_settings_cache[ $post_id ];
		}

		// 1. Load global settings as baseline.
		$settings    = SettingsHelper::get_setting( 'integrations' );
		$cl_settings = $settings['classifiedListing'] ?? array();

		// 2. Load per-form field properties.
		$field = self::getBookingFieldFromForm( $post_id );
		if ( empty( $field ) ) {
			// Do not cache: during a frontend form submit, save_post fires
			// before CL writes _rtcl_form_id, so the lookup is transiently
			// empty. Caching here would poison later reads in the same
			// request and cause a second service to be created at publish.
			return $cl_settings;
		}

		// 3. Override each setting only if the per-form value is explicitly set.
		// Both '' (legacy) and 'use_global' (current sentinel) mean "no override".

		// Mapping mode (select: 'use_global', 'service', 'staff').
		$mapping_mode_val = $field['rtrb_mapping_mode'] ?? '';
		if ( ! empty( $mapping_mode_val ) && 'use_global' !== $mapping_mode_val ) {
			$cl_settings['listingMappingMode'] = $mapping_mode_val;
		}

		// Service name only applies when the form explicitly opted into
		// 'staff' mode. Under 'use_global' or 'service' modes the field is
		// hidden in the editor (see the JS dependency in
		// injectEditorSettingsViaJS), so any leftover value is stale and
		// must not override the global defaultServiceName.
		if ( 'staff' === $mapping_mode_val && ! empty( $field['rtrb_service_name'] ) ) {
			$cl_settings['defaultServiceName'] = sanitize_text_field( $field['rtrb_service_name'] );
		}

		// Auto create employee (select: 'use_global', '1' = yes, '0' = no).
		$auto_create_val = $field['rtrb_auto_create_employee'] ?? '';
		if ( '' !== $auto_create_val && false !== $auto_create_val && 'use_global' !== $auto_create_val ) {
			$cl_settings['autoCreateEmployee'] = ( '1' === (string) $auto_create_val || true === $auto_create_val );
		}

		// Sync price.
		$sync_price_val = $field['rtrb_sync_price'] ?? '';
		if ( '' !== $sync_price_val && false !== $sync_price_val && 'use_global' !== $sync_price_val ) {
			$cl_settings['syncPrice'] = ( '1' === (string) $sync_price_val || true === $sync_price_val );
		}

		// Sync description.
		$sync_desc_val = $field['rtrb_sync_description'] ?? '';
		if ( '' !== $sync_desc_val && false !== $sync_desc_val && 'use_global' !== $sync_desc_val ) {
			$cl_settings['syncDescription'] = ( '1' === (string) $sync_desc_val || true === $sync_desc_val );
		}

		// Default duration (0 = use global).
		$duration_val = (int) ( $field['rtrb_default_duration'] ?? 0 );
		if ( $duration_val > 0 ) {
			$cl_settings['defaultDuration'] = $duration_val;
		}

		self::$effective_settings_cache[ $post_id ] = $cl_settings;
		return $cl_settings;
	}

	/**
	 * Invalidate the effective settings cache for a listing (or all listings).
	 *
	 * Call this after writing form-related post meta in the same request, so
	 * later reads pick up the form override instead of stale global values.
	 *
	 * @param int $post_id The listing post ID, or 0 to clear the entire cache.
	 */
	public static function clearCache( int $post_id = 0 ) {
		if ( $post_id > 0 ) {
			unset( self::$effective_settings_cache[ $post_id ] );
		} else {
			self::$effective_settings_cache = array();
		}
	}

	/**
	 * Read the per-form service name from the form's field data.
	 *
	 * @param int $post_id The listing post ID.
	 *
	 * @return string The service name or empty string if not set.
	 */
	public static function getServiceNameFromForm( int $post_id ): string {
		$field = self::getBookingFieldFromForm( $post_id );
		return isset( $field['rtrb_service_name'] ) ? sanitize_text_field( $field['rtrb_service_name'] ) : '';
	}

	/**
	 * Check if the staff email field is enabled for this listing's form.
	 *
	 * @param int $post_id The listing post ID.
	 *
	 * @return bool
	 */
	public static function isStaffEmailEnabledForForm( int $post_id ): bool {
		$field = self::getBookingFieldFromForm( $post_id );
		return ! empty( $field['rtrb_staff_email_enabled'] );
	}

	/**
	 * Check if the staff email field is enabled for a given form ID.
	 *
	 * @param int $form_id The CL form ID.
	 *
	 * @return bool
	 */
	public static function isStaffEmailEnabledForFormId( int $form_id ): bool {
		$field = self::getBookingFieldFromFormId( $form_id );
		return ! empty( $field['rtrb_staff_email_enabled'] );
	}

	/**
	 * Get the rtrb_booking_enabled field data from a listing's form.
	 *
	 * @param int $post_id The listing post ID.
	 *
	 * @return array The field data or empty array.
	 */
	private static function getBookingFieldFromForm( int $post_id ): array {
		$form_id = absint( get_post_meta( $post_id, '_rtcl_form_id', true ) );
		if ( ! $form_id ) {
			return array();
		}
		return self::getBookingFieldFromFormId( $form_id );
	}

	/**
	 * Get the rtrb_booking_enabled field data from a form ID.
	 *
	 * @param int $form_id The CL form ID.
	 *
	 * @return array The field data or empty array.
	 */
	private static function getBookingFieldFromFormId( int $form_id ): array {
		global $wpdb;
		$table       = $wpdb->prefix . 'rtcl_forms';
		$fields_json = $wpdb->get_var( $wpdb->prepare( "SELECT fields FROM {$table} WHERE id = %d", $form_id ) ); // phpcs:ignore WordPress.DB.DirectDatabaseQuery,WordPress.DB.PreparedSQL.InterpolatedNotPrepared

		if ( ! $fields_json ) {
			return array();
		}

		$fields = json_decode( $fields_json, true );
		if ( ! is_array( $fields ) ) {
			return array();
		}

		foreach ( $fields as $field ) {
			if ( isset( $field['name'] ) && '_rtrb_booking_enabled' === $field['name'] ) {
				return $field;
			}
		}

		return array();
	}
}
