<?php
/**
 * Main orchestrator for the Classified Listing <-> Radius Booking integration.
 *
 * @package RadiusTheme\RadiusBooking\Integrations\ClassifiedListing
 */

namespace RadiusTheme\RadiusBooking\Integrations\ClassifiedListing;

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

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

/**
 * Class ClassifiedListingIntegration
 *
 * Bootstraps the Classified Listing integration by registering all hooks
 * when both plugins are active and the integration is enabled.
 */
class ClassifiedListingIntegration {

	/**
	 * @var ListingServiceSync
	 */
	private $serviceSync;

	/**
	 * @var ListingEmployeeSync
	 */
	private $employeeSync;

	/**
	 * Constructor.
	 */
	public function __construct() {
		// Always expose CL active status to the Settings UI.
		add_filter( 'radius_booking_settings_data', array( $this, 'addIntegrationSettingsData' ) );
		// Only proceed if Classified Listing is active.
		if ( ! function_exists( 'rtcl' ) ) {
			return;
		}

		$settings    = SettingsHelper::get_setting( 'integrations' );
		$cl_settings = $settings['classifiedListing'] ?? array();

		if ( empty( $cl_settings['enabled'] ) ) {
			return;
		}

		$this->serviceSync  = new ListingServiceSync();
		$this->employeeSync = new ListingEmployeeSync();

		$this->registerHooks();
	}

	/**
	 * Register all WordPress hooks for the integration.
	 */
	private function registerHooks() {
		$meta_box = new ListingMetaBox();

		// Admin: meta box on listing edit screen.
		add_action( 'add_meta_boxes', array( $meta_box, 'register' ) );
		add_action( 'save_post_rtcl_listing', array( $meta_box, 'save' ), 10, 2 );

		// Sync service when listing is saved (after meta box save).
		add_action( 'save_post_rtcl_listing', array( $this, 'onListingSave' ), 20, 2 );

		// Handle listing deletion/trash.
		add_action( 'wp_trash_post', array( $this, 'onListingTrash' ) );
		add_action( 'before_delete_post', array( $this, 'onListingDelete' ) );

		// Handle post status transitions.
		add_action( 'transition_post_status', array( $this, 'onStatusTransition' ), 10, 3 );

		// Form Builder: register booking preset fields.
		new ListingFormBuilder();

		// Save staff email from the injected frontend field (before sync at priority 20).
		add_action( 'rtcl_listing_form_after_save_or_update', array( $this, 'saveStaffEmailFromForm' ), 15, 2 );

		// Sync service after Form Builder saves (meta is saved after save_post fires).
		add_action( 'rtcl_listing_form_after_save_or_update', array( $this, 'onFormBuilderSave' ), 20, 2 );

		// Enqueue frontend JS for the listing form (injects staff email input).
		add_action( 'wp_enqueue_scripts', array( $this, 'enqueueListingFormAssets' ) );

		// Frontend: render "Book Now" button and booking form on listing pages.
		ListingFrontendHooks::init();

		// Dashboard: add "Bookings" tab to the CL My Account page.
		new ListingDashboardHooks();
	}

	/**
	 * Fired when a listing is saved. Syncs the service and employee.
	 *
	 * @param int      $post_id Post ID.
	 * @param \WP_Post $post    Post object.
	 */
	public function onListingSave( $post_id, $post ) {
		// Skip autosave and revisions.
		if ( defined( 'DOING_AUTOSAVE' ) && DOING_AUTOSAVE ) {
			return;
		}
		if ( wp_is_post_revision( $post_id ) ) {
			return;
		}
		if ( 'rtcl_listing' !== $post->post_type ) {
			return;
		}

		// Use per-form effective settings (merges form overrides with global).
		$cl_settings = ListingFormBuilder::getEffectiveSettings( $post_id );

		if ( $this->serviceSync->isStaffMode( $post_id ) ) {
			// Staff mode: listing becomes employee, shared default service.
			if ( ! $this->serviceSync->isListingBookable( $post_id ) ) {
				$this->employeeSync->deactivateEmployeeForListing( $post_id );
				return;
			}
			$form_service_name = $cl_settings['defaultServiceName'] ?? '';
			$staff_email       = (string) get_post_meta( $post_id, '_rtrb_staff_email', true );
			$service           = $this->serviceSync->getOrCreateDefaultService( $cl_settings, $form_service_name );
			if ( $service ) {
				$this->employeeSync->ensureEmployeeForListing( $post_id, $service->id, $staff_email );
			}
		} else {
			// Service mode: listing becomes service, author becomes employee.
			$service = $this->serviceSync->syncServiceFromListing( $post_id );
			if ( $service && ! empty( $cl_settings['autoCreateEmployee'] ) ) {
				$this->employeeSync->ensureEmployeeForListingOwner( $post_id, $service->id );
			}
		}
	}

	/**
	 * Fired after the Form Builder saves a listing (meta is already persisted).
	 *
	 * @param \Rtcl\Models\Listing|null $listing Listing model.
	 * @param string                    $postingType 'new' or 'update'.
	 */
	public function onFormBuilderSave( $listing, $postingType ) {
		if ( ! $listing ) {
			return;
		}

		$post_id = $listing->get_id();

		// CL just wrote _rtcl_form_id and _rtrb_booking_enabled meta. Drop any
		// cached effective settings from the earlier save_post pass (where
		// form_id was not yet visible) so we read the form's per-element
		// overrides instead of the global defaults.
		ListingFormBuilder::clearCache( $post_id );

		$cl_settings = ListingFormBuilder::getEffectiveSettings( $post_id );

		if ( $this->serviceSync->isStaffMode( $post_id ) ) {
			if ( ! $this->serviceSync->isListingBookable( $post_id ) ) {
				$this->employeeSync->deactivateEmployeeForListing( $post_id );
				return;
			}
			$form_service_name = $cl_settings['defaultServiceName'] ?? '';
			$staff_email       = (string) get_post_meta( $post_id, '_rtrb_staff_email', true );
			$service           = $this->serviceSync->getOrCreateDefaultService( $cl_settings, $form_service_name );
			if ( $service ) {
				$this->employeeSync->ensureEmployeeForListing( $post_id, $service->id, $staff_email );
			}
		} else {
			$service = $this->serviceSync->syncServiceFromListing( $post_id );
			if ( $service && ! empty( $cl_settings['autoCreateEmployee'] ) ) {
				$this->employeeSync->ensureEmployeeForListingOwner( $post_id, $service->id );
			}
		}
	}

	/**
	 * Save staff email from the injected frontend form field.
	 *
	 * @param \Rtcl\Models\Listing|null $listing     Listing model.
	 * @param string                    $postingType 'new' or 'update'.
	 */
	public function saveStaffEmailFromForm( $listing, $postingType ) {
		if ( ! $listing ) {
			return;
		}

		// phpcs:ignore WordPress.Security.NonceVerification.Missing -- nonce verified by CL's form handler.
		$staff_email = isset( $_POST['_rtrb_staff_email'] ) ? sanitize_email( wp_unslash( $_POST['_rtrb_staff_email'] ) ) : '';

		if ( ! empty( $staff_email ) ) {
			update_post_meta( $listing->get_id(), '_rtrb_staff_email', $staff_email );
		}
	}

	/**
	 * Enqueue JavaScript on the listing form page to inject the staff email field.
	 * Only enqueues when the form has staff email enabled via the Radius Booking element.
	 */
	public function enqueueListingFormAssets() {
		if ( is_admin() ) {
			return;
		}

		$current_user  = wp_get_current_user();
		$current_email = $current_user->user_email ?? '';
		$is_staff_mode       = false;
		// Strict default: only show the Staff Email Field when we can confirm
		// the form's toggle is on. The JS layer overrides this by reading the
		// real rtrb element settings from window.rtclFB once CL renders the
		// chosen form's fields.
		$staff_email_enabled = false;

		// phpcs:ignore WordPress.Security.NonceVerification.Recommended
		$listing_id = isset( $_GET['listing_id'] ) ? absint( $_GET['listing_id'] ) : 0;
		if ( $listing_id ) {
			// Editing: read effective mapping + per-form toggle from the
			// listing's form (resolved via _rtcl_form_id post meta).
			$cl_settings         = ListingFormBuilder::getEffectiveSettings( $listing_id );
			$is_staff_mode       = ( $cl_settings['listingMappingMode'] ?? 'service' ) === 'staff';
			$staff_email_enabled = ListingFormBuilder::isStaffEmailEnabledForForm( $listing_id );

			$saved_email = (string) get_post_meta( $listing_id, '_rtrb_staff_email', true );
			if ( ! empty( $saved_email ) ) {
				$current_email = $saved_email;
			}
		} else {
			// New listing: form_id isn't in $_GET on initial render, so the
			// JS layer is responsible for reading the toggle from rtclFB.
			$is_staff_mode = $this->serviceSync->isStaffMode();
		}

		wp_enqueue_script(
			'rtrb-cl-listing-form',
			RADIUS_BOOKING_URL . '/assets/js/cl-listing-form.js',
			array(),
			RADIUS_BOOKING_VERSION,
			true
		);

		wp_localize_script( 'rtrb-cl-listing-form', 'rtrbClForm', array(
			'isStaffMode'           => $is_staff_mode,
			'staffEmailEnabled'     => $staff_email_enabled,
			'staffEmailLabel'       => __( 'Staff Email', 'radius-booking' ),
			'staffEmailPlaceholder' => __( 'staff@example.com', 'radius-booking' ),
			'staffEmailHelp'        => __( 'Email address for creating the staff member in Radius Booking.', 'radius-booking' ),
			'staffEmailRequired'    => __( 'Staff email is required.', 'radius-booking' ),
			'currentStaffEmail'     => $current_email,
		) );
	}

	/**
	 * When a listing is trashed, hide the mirrored service.
	 *
	 * @param int $post_id Post ID.
	 */
	public function onListingTrash( $post_id ) {
		if ( 'rtcl_listing' !== get_post_type( $post_id ) ) {
			return;
		}
		if ( $this->serviceSync->isStaffMode( $post_id ) ) {
			$this->employeeSync->deactivateEmployeeForListing( $post_id );
		} else {
			$this->serviceSync->unlinkServiceFromListing( $post_id );
		}
	}

	/**
	 * When a listing is permanently deleted, hide the mirrored service or deactivate the employee.
	 *
	 * @param int $post_id Post ID.
	 */
	public function onListingDelete( $post_id ) {
		if ( 'rtcl_listing' !== get_post_type( $post_id ) ) {
			return;
		}
		if ( $this->serviceSync->isStaffMode( $post_id ) ) {
			$this->employeeSync->deactivateEmployeeForListing( $post_id );
		} else {
			$this->serviceSync->unlinkServiceFromListing( $post_id );
		}
	}

	/**
	 * Handle post status transitions for listings.
	 *
	 * @param string   $new_status New post status.
	 * @param string   $old_status Old post status.
	 * @param \WP_Post $post       Post object.
	 */
	public function onStatusTransition( $new_status, $old_status, $post ) {
		if ( 'rtcl_listing' !== $post->post_type ) {
			return;
		}

		if ( ! $this->serviceSync->isListingBookable( $post->ID ) ) {
			return;
		}

		if ( $this->serviceSync->isStaffMode( $post->ID ) ) {
			// Staff mode: toggle employee active/inactive based on listing status.
			if ( 'publish' === $new_status ) {
				$this->employeeSync->activateEmployeeForListing( $post->ID );
			} elseif ( in_array( $new_status, array( 'draft', 'pending', 'trash', 'expired', 'rtcl-expired' ), true ) ) {
				$this->employeeSync->deactivateEmployeeForListing( $post->ID );
			}
			return;
		}

		// Service mode: toggle service visibility.
		$service = $this->serviceSync->findServiceByListing( $post->ID );
		if ( ! $service ) {
			return;
		}

		if ( 'publish' === $new_status ) {
			Service::where( 'id', $service->id )->update( array(
				'status'     => 'visible',
				'is_visible' => 1,
			) );
		} elseif ( in_array( $new_status, array( 'draft', 'pending', 'trash', 'expired', 'rtcl-expired' ), true ) ) {
			Service::where( 'id', $service->id )->update( array(
				'status'     => 'hidden',
				'is_visible' => 0,
			) );
		}
	}

	/**
	 * Add CL integration data to settings response.
	 *
	 * @param array $settings_data The settings data array.
	 *
	 * @return array
	 */
	public function addIntegrationSettingsData( $settings_data ) {
		$settings_data['integrations']['classifiedListing']['is_cl_active'] = function_exists( 'rtcl' );
		return $settings_data;
	}
}
