<?php
/**
 * TimePeriodServiceSyncService
 */

namespace RadiusTheme\RadiusBooking\Services\EmployeeServices;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}
use RadiusTheme\RadiusBooking\Core\Support\Collection;
use RadiusTheme\RadiusBooking\Models\EmployeeWeekdayTimePeriodService;
use RadiusTheme\RadiusBooking\Repositories\UserRepository;

/**
 * TimePeriodServiceSyncService
 *
 * A service class responsible for synchronizing user weekday time period services.
 */
class TimePeriodServiceSyncService {

	/**
	 * The user repository instance.
	 *
	 * @var UserRepository $userRepo
	 */
	private UserRepository $userRepo;

	/**
	 * Constructor
	 *
	 * @param UserRepository $userRepo  User repository instance.
	 */
	public function __construct( UserRepository $userRepo ) {
		$this->userRepo = $userRepo;
	}
	/**
	 * Sync user weekday time period services
	 *
	 * @param int $time_period_id  The ID of the time period.
	 * @param array $services  An array of services to be associated with the time period.
	 * @throws \Exception  If there is an error during the synchronization process.
	 */
	public function syncUserWeekdayTimePeriodService( $time_period_id, $services ) {
		try {
			$this->validateServices( $services );
			$this->deleteRemovedServices( $time_period_id, $services );
			$this->saveServices( $time_period_id, $services );

		} catch ( \Exception $e ) {
			error_log( 'Error syncing user weekday time period service: ' . $e->getMessage() );
			throw $e;
		}
	}

	/**
	 * Validates the provided services.
	 *
	 * @param array $services Array of services to be validated.
	 *
	 * @return void
	 * @throws \InvalidArgumentException If the provided argument is not a non-empty array.
	 */
	private function validateServices( $services ) {
		if ( ! is_array( $services ) ) {
			throw new \InvalidArgumentException( 'Services must be a non-empty array' );
		}
	}

	/**
	 * Deletes services associated with a specific time period that are not in the provided list of services.
	 *
	 * @param int $time_period_id The ID of the time period.
	 * @param array $services An array of services to retain.
	 *
	 * @return void
	 */
	private function deleteRemovedServices( $time_period_id, $services ) {
		if ( empty( $services ) ) {
			$this->userRepo->deleteAllTimePeriodServices( $time_period_id );
			return;
		}

		$serviceIds = ( new Collection( $services ) )->pluck( 'id' );

		if ( empty( $serviceIds ) ) {
			return;
		}
		$this->userRepo->deleteTimePeriodServicesNotInList( $time_period_id, $serviceIds );
	}

	/**
	 * Saves a list of services for a given time period.
	 *
	 * @param int $time_period_id The ID of the time period to associate the services with.
	 * @param array $services An array of service data to be validated and saved.
	 *
	 * @return void
	 */
	private function saveServices( $time_period_id, $services ) {
		foreach ( $services as $service ) {
			$this->validateServiceData( $service );
			$this->saveService( $time_period_id, $service );
		}
	}

	/**
	 * Validates the given service data.
	 *
	 * @param array $service The service data to validate.
	 *
	 * @return void
	 * @throws \InvalidArgumentException If the 'service_id' key is not set in the service data.
	 */
	private function validateServiceData( $service ) {
		if ( ! isset( $service['service_id'] ) ) {
			throw new \InvalidArgumentException( 'Service ID is required' );
		}
	}

	/**
	 * Saves or updates the service data for a given time period.
	 *
	 * @param int $time_period_id Identifier for the weekday time period.
	 * @param array $service Associative array containing service details, including optional 'id' and 'service_id'.
	 *
	 * @return void
	 */
	private function saveService( $time_period_id, $service ) {
		$employeeService = isset( $service['id'] )
			? EmployeeWeekdayTimePeriodService::findOrNew( $service['id'] )
			: new EmployeeWeekdayTimePeriodService();

		$employeeService->fill(
			array(
				'weekday_time_period_id' => $time_period_id,
				'service_id'             => $service['service_id'],
			)
		);

		$employeeService->save();
	}
}
