<?php
/**
 * Syncs Classified Listing data to a mirrored Radius Booking service record.
 *
 * @package RadiusTheme\RadiusBooking\Integrations\ClassifiedListing
 */

namespace RadiusTheme\RadiusBooking\Integrations\ClassifiedListing;

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

use RadiusTheme\RadiusBooking\Core\Container\Container;
use RadiusTheme\RadiusBooking\Helpers\SettingsHelper;
use RadiusTheme\RadiusBooking\Models\Service;
use RadiusTheme\RadiusBooking\Repositories\ServiceRepository;

/**
 * Class ListingServiceSync
 *
 * Handles creating, updating, and hiding the mirrored Service record
 * for a Classified Listing post.
 */
class ListingServiceSync {

	/**
	 * Check if the integration is in "staff" mapping mode.
	 *
	 * When a post_id is given, checks the per-form override first,
	 * then falls back to the global setting.
	 *
	 * @param int $post_id Optional listing post ID for per-form mode check.
	 *
	 * @return bool
	 */
	public function isStaffMode( int $post_id = 0 ): bool {
		if ( $post_id > 0 ) {
			$cl_settings = ListingFormBuilder::getEffectiveSettings( $post_id );
		} else {
			$settings    = SettingsHelper::get_setting( 'integrations' );
			$cl_settings = $settings['classifiedListing'] ?? array();
		}
		return ( $cl_settings['listingMappingMode'] ?? 'service' ) === 'staff';
	}

	/**
	 * Get or create the shared default service used in staff mode.
	 *
	 * @param array  $cl_settings       The classified listing settings.
	 * @param string $form_service_name Optional per-form service name override.
	 *
	 * @return Service|null The default service or null on failure.
	 */
	public function getOrCreateDefaultService( array $cl_settings = array(), string $form_service_name = '' ) {
		if ( empty( $cl_settings ) ) {
			$settings    = SettingsHelper::get_setting( 'integrations' );
			$cl_settings = $settings['classifiedListing'] ?? array();
		}

		// When no per-form name is given, use original behavior exactly.
		if ( empty( $form_service_name ) ) {
			// Check stored service ID first.
			$stored_id = get_option( 'rtrb_cl_default_service_id', 0 );
			if ( $stored_id ) {
				$service = Service::find( $stored_id );
				if ( $service ) {
					return $service;
				}
			}

			// Fallback: find by source_type.
			$service = Service::where( 'source_type', 'classified_listing_default' )->first();
			if ( $service ) {
				update_option( 'rtrb_cl_default_service_id', $service->id );
				return $service;
			}
		} else {
			// Per-form name given: find existing service with this exact name.
			$service = Service::where( 'source_type', 'classified_listing_default' )
				->where( 'name', $form_service_name )
				->first();
			if ( $service ) {
				return $service;
			}
		}

		// Create a new default service.
		$service_name     = ! empty( $form_service_name ) ? $form_service_name : ( $cl_settings['defaultServiceName'] ?? __( 'Consultation', 'radius-booking' ) );
		$default_duration = (int) ( $cl_settings['defaultDuration'] ?? 60 );
		$default_category = (int) ( $cl_settings['defaultCategory'] ?? 0 );

		$service = Service::create( array(
			'name'               => $service_name,
			'description'        => '',
			'color'              => '',
			'price'              => 0,
			'duration'           => $default_duration * 60,
			'category_id'        => $default_category,
			'listing_id'         => null,
			'source_type'        => 'classified_listing_default',
			'status'             => 'visible',
			'is_visible'         => 1,
			'min_capacity'       => 1,
			'max_capacity'       => 1,
			'time_before'        => 0,
			'time_after'         => 0,
			'bringing_anyone'    => 0,
			'priority'           => 'least_occupied',
			'position'           => 0,
			'aggregated_price'   => 1,
			'settings'           => array(
				'general'        => array(
					'defaultStatus'        => 'global',
					'minBookingTime'       => 'disabled',
					'minCancelTime'        => 'disabled',
					'minRescheduleTime'    => 'disabled',
					'bookingAdvancePeriod' => 365,
					'redirectUrl'          => '',
				),
				'paymentMethods' => array(
					'stripe'  => '',
					'paypal'  => '',
					'offline' => 1,
				),
				'integrations'   => array(
					'googleCalender' => '',
					'googleMeet'     => '',
					'zoom'           => '',
				),
			),
			'recurring_cycle'     => 'disabled',
			'recurring_sub'       => 'future',
			'recurring_payment'   => 0,
			'deposit_payment'     => 0,
			'deposit_type'        => 'fixed',
			'deposit_per_person'  => 0,
			'deposit'             => 0,
			'full_payment'        => 0,
			'mandatory_extra'     => 0,
			'min_selected_extras' => 0,
			'custom_pricing'      => null,
			'max_extra_people'    => 0,
			'limit_per_customer'  => null,
			'translations'        => null,
			'picture_full_path'   => '',
			'picture_thumb_path'  => '',
		) );

		if ( $service && $service->id ) {
			update_option( 'rtrb_cl_default_service_id', $service->id );
		}

		return $service;
	}

	/**
	 * Sync (create or update) a Radius Booking service from a listing.
	 *
	 * @param int $listing_id The WP post ID of the rtcl_listing.
	 *
	 * @return Service|null The synced service or null on failure.
	 */
	public function syncServiceFromListing( int $listing_id ) {
		if ( ! $this->isListingBookable( $listing_id ) ) {
			$this->unlinkServiceFromListing( $listing_id );
			return null;
		}

		$post = get_post( $listing_id );
		if ( ! $post || 'publish' !== $post->post_status ) {
			return null;
		}

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

		// In staff mode, return the shared default service instead of per-listing service.
		if ( $this->isStaffMode( $listing_id ) ) {
			return $this->getOrCreateDefaultService( $cl_settings );
		}
		$default_duration = (int) ( $cl_settings['defaultDuration'] ?? 60 );
		$default_category = (int) ( $cl_settings['defaultCategory'] ?? 0 );
		$sync_price       = $cl_settings['syncPrice'] ?? true;
		$sync_description = $cl_settings['syncDescription'] ?? true;

		// Gather listing data.
		$name        = $post->post_title;
		$description = $sync_description ? wp_strip_all_tags( $post->post_content ) : '';
		$price       = $sync_price ? (float) get_post_meta( $listing_id, '_rtcl_price', true ) : 0;
		if ( ! $price ) {
			$price = $sync_price ? (float) get_post_meta( $listing_id, 'price', true ) : 0;
		}
		$duration    = (int) get_post_meta( $listing_id, '_rtrb_booking_duration', true );
		if ( ! $duration ) {
			$duration = $default_duration;
		}
		$category_id = (int) get_post_meta( $listing_id, '_rtrb_booking_category_id', true );
		if ( ! $category_id ) {
			$category_id = $default_category;
		}

		// Featured image as service picture.
		$picture_url = get_the_post_thumbnail_url( $listing_id, 'full' );
		$thumb_url   = get_the_post_thumbnail_url( $listing_id, 'thumbnail' );

		// Find existing service for this listing.
		$service = Service::where( 'listing_id', $listing_id )->first();

		$data = array(
			'name'               => $name,
			'description'        => mb_substr( $description, 0, 5000 ),
			'color'              => '',
			'price'              => $price,
			'duration'           => $duration * 60,
			'category_id'        => $category_id,
			'listing_id'         => $listing_id,
			'source_type'        => 'classified_listing',
			'status'             => 'visible',
			'is_visible'         => 1,
			'min_capacity'       => 1,
			'max_capacity'       => 1,
			'time_before'        => 0,
			'time_after'         => 0,
			'bringing_anyone'    => 0,
			'priority'           => 'least_occupied',
			'position'           => 0,
			'aggregated_price'   => 1,
			'settings' =>  array(
				'general'        => array(
					'defaultStatus'        => 'global',
					'minBookingTime'       => 'disabled',
					'minCancelTime'        => 'disabled',
					'minRescheduleTime'    => 'disabled',
					'bookingAdvancePeriod' => 365,
					'redirectUrl'          => '',
				),
				'paymentMethods' => array(
					'stripe'  => '',
					'paypal'  => '',
					'offline' => 1,
				),
				'integrations'   => array(
					'googleCalender' => '',
					'googleMeet'     => '',
					'zoom'           => '',
				),
			),
			'recurring_cycle'    => 'disabled',
			'recurring_sub'      => 'future',
			'recurring_payment'  => 0,
			'deposit_payment'    => 0,
			'deposit_type'       => 'fixed',
			'deposit_per_person' => 0,
			'deposit'            => 0,
			'full_payment'       => 0,
			'mandatory_extra'    => 0,
			'min_selected_extras' => 0,
			'custom_pricing'     => null,
			'max_extra_people'   => 0,
			'limit_per_customer' => null,
			'translations'       => null,
			'picture_full_path'  => $picture_url ?: '',
			'picture_thumb_path' => $thumb_url ?: '',
		);

		if ( $service ) {
			$old_price = (float) $service->price;

			// Update only synced fields; keep other settings intact.
			$update_data = array(
				'name'               => $data['name'],
				'price'              => $data['price'],
				'duration'           => $data['duration'],
				'category_id'        => $data['category_id'],
				'status'             => 'visible',
				'is_visible'         => 1,
				'picture_full_path'  => $data['picture_full_path'],
				'picture_thumb_path' => $data['picture_thumb_path'],
			);
			if ( $sync_description ) {
				$update_data['description'] = $data['description'];
			}
			Service::where( 'id', $service->id )->update( $update_data );

			// Shift each employee's override by the same delta so custom
			// prices stay relative to the new listing price.
			if ( $sync_price ) {
				$delta = (float) $data['price'] - $old_price;
				if ( 0.0 !== $delta ) {
					Container::resolve( ServiceRepository::class )
						->applyPriceDeltaToEmployees( (int) $service->id, $delta );
				}
			}
			$service = Service::find( $service->id );
		} else {
			$service = Service::create( $data );
		}

		return $service;
	}

	/**
	 * Hide the service linked to a listing (preserves appointment history).
	 *
	 * @param int $listing_id The WP post ID of the rtcl_listing.
	 */
	public function unlinkServiceFromListing( int $listing_id ) {
		$service = Service::where( 'listing_id', $listing_id )->first();
		if ( $service ) {
			Service::where( 'id', $service->id )->update( array(
				'status'     => 'hidden',
				'is_visible' => 0,
			) );
		}
	}

	/**
	 * Normalize the `_rtrb_booking_enabled` meta value to a real boolean.
	 *
	 * The wp-admin metabox stores 1/0, but the Classified Listing frontend
	 * form builder persists a 'switch' field as the string 'yes'/'no'. A naive
	 * `(bool)` cast treats the string 'no' as true, so a disabled listing kept
	 * showing the Book Now button. Treat only explicit enable values as true.
	 *
	 * @param mixed $value Raw meta value.
	 *
	 * @return bool
	 */
	public static function normalizeBookingEnabled( $value ): bool {
		if ( is_string( $value ) ) {
			$value = strtolower( trim( $value ) );
		}

		return in_array( $value, array( 1, '1', true, 'yes', 'on', 'true' ), true );
	}

	/**
	 * Check if a listing has booking enabled.
	 *
	 * @param int $listing_id The WP post ID.
	 *
	 * @return bool
	 */
	public function isListingBookable( int $listing_id ): bool {
		return self::normalizeBookingEnabled( get_post_meta( $listing_id, '_rtrb_booking_enabled', true ) );
	}

	/**
	 * Find the service linked to a listing.
	 *
	 * @param int $listing_id The WP post ID.
	 *
	 * @return Service|null
	 */
	public function findServiceByListing( int $listing_id ) {
		return Service::where( 'listing_id', $listing_id )->first();
	}
}
