<?php
/**
 * Maps a Classified Listing owner to a Radius Booking employee.
 *
 * @package RadiusTheme\RadiusBooking\Integrations\ClassifiedListing
 */

namespace RadiusTheme\RadiusBooking\Integrations\ClassifiedListing;

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

use RadiusTheme\RadiusBooking\Models\EmployeeService;
use RadiusTheme\RadiusBooking\Models\Service;
use RadiusTheme\RadiusBooking\Models\User;
use RadiusTheme\RadiusBooking\Models\UserProfile;

/**
 * Class ListingEmployeeSync
 *
 * Ensures the listing owner has a corresponding employee record
 * in Radius Booking and is assigned to the mirrored service.
 */
class ListingEmployeeSync {

	/**
	 * Ensure the listing owner exists as a Radius Booking employee
	 * and is assigned to the given service.
	 *
	 * @param int $listing_id The WP post ID of the listing.
	 * @param int $service_id The Radius Booking service ID.
	 *
	 * @return int|null The Radius Booking user ID, or null on failure.
	 */
	public function ensureEmployeeForListingOwner( int $listing_id, int $service_id ) {
		$post = get_post( $listing_id );
		if ( ! $post ) {
			return null;
		}

		$wp_user_id = (int) $post->post_author;
		$wp_user    = get_userdata( $wp_user_id );
		if ( ! $wp_user ) {
			return null;
		}

		// Look up the WP user's "author" employee identity — a profile with
		// no listing_id. Listing-tied profiles (staff mode) intentionally use
		// per-listing staff emails, so service mode must not reuse them or the
		// service's employee row would inherit the wrong email.
		$profile = UserProfile::where( 'wp_user_id', $wp_user_id )
			->whereNull( 'listing_id' )
			->first();

		$rb_user_id = null;

		if ( $profile ) {
			$rb_user_id = $profile->user_id;
			$user       = User::find( $rb_user_id );
			$updates    = array();
			if ( $user && 'employee' !== $user->get_type() ) {
				$updates['user_type'] = 'employee';
			}
			// Keep the email aligned with the WP user's email so the service
			// mode employee always reflects the listing author, even if a
			// previous flow wrote a different value here.
			if ( $user && $user->email !== $wp_user->user_email ) {
				$updates['email'] = $wp_user->user_email;
			}
			if ( ! empty( $updates ) ) {
				User::where( 'id', $rb_user_id )->update( $updates );
			}
		} else {
			// Create a new Radius Booking employee record.
			$user = User::create( array(
				'user_type' => 'employee',
				'email'     => $wp_user->user_email,
				'status'    => 'active',
			) );

			if ( ! $user || ! $user->get_id() ) {
				return null;
			}

			$rb_user_id = $user->get_id();

			// Create user profile (no listing_id — this is the author identity).
			UserProfile::create( array(
				'user_id'    => $rb_user_id,
				'wp_user_id' => $wp_user_id,
				'first_name' => $wp_user->first_name ?: $wp_user->display_name,
				'last_name'  => $wp_user->last_name ?: '',
			) );

			// Add the WordPress role.
			$wp_user->add_role( 'radius_booking_employee' );
		}

		if ( ! $rb_user_id ) {
			return null;
		}

		// Assign the employee to the service (if not already assigned).
		$existing = EmployeeService::where( 'user_id', $rb_user_id )
			->where( 'service_id', $service_id )
			->first();
		$price = (Service::find( $service_id ))->get_price();

		if ( ! $existing ) {
			EmployeeService::create( array(
				'user_id'    => $rb_user_id,
				'service_id' => $service_id,
				'min_capacity' => 1,
				'max_capacity' => 1,
				'price'      => $price,
			) );
		}

		return $rb_user_id;
	}

	/**
	 * Get the Radius Booking employee user ID for a listing owner.
	 *
	 * @param int $listing_id The WP post ID of the listing.
	 *
	 * @return int|null
	 */
	public function getEmployeeIdForListing( int $listing_id ) {
		$post = get_post( $listing_id );
		if ( ! $post ) {
			return null;
		}

		$wp_user_id = (int) $post->post_author;
		$profile    = UserProfile::where( 'wp_user_id', $wp_user_id )->first();

		return $profile ? $profile->user_id : null;
	}

	/**
	 * Ensure an employee exists for a listing in staff mode.
	 * The listing data (title, image) is used as the employee profile.
	 *
	 * @param int    $listing_id  The WP post ID of the listing.
	 * @param int    $service_id  The shared default service ID.
	 * @param string $staff_email Optional staff email from form. Falls back to listing author email.
	 *
	 * @return int|null The Radius Booking user ID, or null on failure.
	 */
	public function ensureEmployeeForListing( int $listing_id, int $service_id, string $staff_email = '' ) {
		$post = get_post( $listing_id );
		if ( ! $post ) {
			return null;
		}

		$wp_user_id = (int) $post->post_author;
		$wp_user    = get_userdata( $wp_user_id );
		if ( ! $wp_user ) {
			return null;
		}

		// Use staff email from form if provided, otherwise fall back to WP user email.
		$employee_email = ! empty( $staff_email ) ? sanitize_email( $staff_email ) : $wp_user->user_email;

		// Parse listing title into first and last name.
		list( $first_name, $last_name ) = $this->splitName( $post->post_title );

		// Get featured image attachment ID.
		$image_id = get_post_thumbnail_id( $listing_id );

		// Check if an employee already exists for this listing.
		$profile = UserProfile::where( 'listing_id', $listing_id )->first();

		$rb_user_id = null;

		if ( $profile ) {
			$rb_user_id = $profile->user_id;

			// Ensure the user type is employee.
			$user = User::find( $rb_user_id );
			if ( $user && 'employee' !== $user->get_type() ) {
				User::where( 'id', $rb_user_id )->update( array( 'user_type' => 'employee' ) );
			}

			// Re-activate if previously deactivated.
			if ( $user && 'active' !== $user->status ) {
				User::where( 'id', $rb_user_id )->update( array( 'status' => 'active' ) );
			}

			// Update email if staff email was provided and differs.
			if ( ! empty( $staff_email ) && $user && $user->email !== $employee_email ) {
				User::where( 'id', $rb_user_id )->update( array( 'email' => $employee_email ) );
			}

			// Update profile with latest listing data.
			UserProfile::where( 'id', $profile->id )->update( array(
				'first_name' => $first_name,
				'last_name'  => $last_name,
				'image_id'   => $image_id ?: null,
			) );
		} else {
			// Create a new employee from listing data.
			$user = User::create( array(
				'user_type' => 'employee',
				'email'     => $employee_email,
				'status'    => 'active',
			) );

			if ( ! $user || ! $user->get_id() ) {
				return null;
			}

			$rb_user_id = $user->get_id();

			// Create user profile from listing data.
			UserProfile::create( array(
				'user_id'     => $rb_user_id,
				'wp_user_id'  => $wp_user_id,
				'listing_id'  => $listing_id,
				'source_type' => 'classified_listing',
				'first_name'  => $first_name,
				'last_name'   => $last_name,
				'image_id'    => $image_id ?: null,
			) );

			// Add the WordPress role.
			$wp_user->add_role( 'radius_booking_employee' );
		}

		if ( ! $rb_user_id ) {
			return null;
		}

		// Assign the employee to the service (if not already assigned).
		$existing = EmployeeService::where( 'user_id', $rb_user_id )
			->where( 'service_id', $service_id )
			->first();

		// Use listing price as custom pricing for this employee.
		$price = (float) get_post_meta( $listing_id, '_rtcl_price', true );
		if ( ! $price ) {
			$price = (float) get_post_meta( $listing_id, 'price', true );
		}

		if ( ! $existing ) {
			EmployeeService::create( array(
				'user_id'      => $rb_user_id,
				'service_id'   => $service_id,
				'min_capacity' => 1,
				'max_capacity' => 1,
				'price'        => $price,
			) );
		} else {
			// Update price if changed.
			EmployeeService::where( 'id', $existing->id )->update( array(
				'price' => $price,
			) );
		}

		return $rb_user_id;
	}

	/**
	 * Get the employee ID for a listing in staff mode (by listing_id on profile).
	 *
	 * @param int $listing_id The WP post ID of the listing.
	 *
	 * @return int|null
	 */
	public function getEmployeeIdForListingStaffMode( int $listing_id ) {
		$profile = UserProfile::where( 'listing_id', $listing_id )->first();
		return $profile ? $profile->user_id : null;
	}

	/**
	 * Deactivate the employee linked to a listing (staff mode).
	 *
	 * @param int $listing_id The WP post ID of the listing.
	 */
	public function deactivateEmployeeForListing( int $listing_id ) {
		$profile = UserProfile::where( 'listing_id', $listing_id )->first();
		if ( $profile ) {
			User::where( 'id', $profile->user_id )->update( array( 'status' => 'inactive' ) );
		}
	}

	/**
	 * Activate the employee linked to a listing (staff mode).
	 *
	 * @param int $listing_id The WP post ID of the listing.
	 */
	public function activateEmployeeForListing( int $listing_id ) {
		$profile = UserProfile::where( 'listing_id', $listing_id )->first();
		if ( $profile ) {
			User::where( 'id', $profile->user_id )->update( array( 'status' => 'active' ) );
		}
	}

	/**
	 * Split a full name string into first and last name.
	 *
	 * @param string $name The full name.
	 *
	 * @return array [ first_name, last_name ]
	 */
	private function splitName( string $name ): array {
		$name = trim( $name );
		$pos  = strrpos( $name, ' ' );
		if ( false === $pos ) {
			return array( $name, '' );
		}
		return array(
			trim( substr( $name, 0, $pos ) ),
			trim( substr( $name, $pos + 1 ) ),
		);
	}
}
