<?php
/**
 * TimePeriodLocationSyncService
 */

namespace RadiusTheme\RadiusBooking\Services\EmployeeServices;

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

/**
 * Service to handle synchronization of weekday time period locations for users.
 * This class is responsible for managing user-assigned locations for specific time periods,
 * validating the input data, removing obsolete location entries, and saving new or updated ones.
 */
class TimePeriodLocationSyncService {

	/**
	 * 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;
	}

	/**
	 * Synchronizes the user's weekday time period location by validating, removing, and saving location data for the given time period.
	 *
	 * @param int $time_period_id The identifier for the time period to update locations for.
	 * @param array $locations An array of location data to be synchronized for the specified time period.
	 *
	 * @return void
	 * @throws \Exception If an error occurs during synchronization.
	 */
	public function syncUserWeekdayTimePeriodLocation( $time_period_id, $locations ) {
		try {
			$this->validateLocations( $locations );
			$this->deleteRemovedLocations( $time_period_id, $locations );
			$this->saveLocations( $time_period_id, $locations );

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

	/**
	 * Validates the locations provided to ensure they meet the required criteria.
	 *
	 * @param array $locations An array of location data to be validated.
	 *
	 * @return void
	 * @throws \InvalidArgumentException If the provided locations are not a non-empty array.
	 */
	private function validateLocations( $locations ) {
		if ( ! is_array( $locations ) ) {
			throw new \InvalidArgumentException( 'Locations must be a non-empty array' );
		}
	}

	/**
	 * Deletes any locations associated with the specified time period that are not present in the provided list of locations.
	 *
	 * @param int $time_period_id The identifier for the time period whose locations should be checked and removed if necessary.
	 * @param array $locations An array of location data to retain for the specified time period.
	 *
	 * @return void
	 */
	private function deleteRemovedLocations( $time_period_id, $locations ) {
		if ( empty( $locations ) ) {
			$this->userRepo->deleteAllTimePeriodLocation( $time_period_id );
			return;
		}
		$locationIds = ( new Collection( $locations ) )->pluck( 'id' );

		if ( ! empty( $locationIds ) ) {
			$this->userRepo->deleteTimePeriodLocationNotInList( $locations, $time_period_id, $locationIds );
		}
	}

	/**
	 * Saves the provided locations for a specific time period by validating and saving each location individually.
	 *
	 * @param int $time_period_id The identifier of the time period for which the locations are being saved.
	 * @param array $locations An array containing the location data to be saved for the specified time period.
	 *
	 * @return void
	 * @throws \Exception If an error occurs during validation or saving of location data.
	 */
	private function saveLocations( $time_period_id, $locations ) {
		foreach ( $locations as $location ) {
			$this->validateLocationData( $location );
			$this->saveLocation( $time_period_id, $location );
		}
	}

	/**
	 * Validates the given location data to ensure required fields are present.
	 *
	 * @param array $location An associative array containing location data to be validated.
	 *
	 * @return void
	 * @throws \InvalidArgumentException If the location data is missing a required 'location_id' field.
	 */
	private function validateLocationData( $location ) {
		if ( ! isset( $location['location_id'] ) ) {
			throw new \InvalidArgumentException( 'Location ID is required' );
		}
	}

	/**
	 * Saves or updates a location for a specific weekday time period.
	 *
	 * @param int $time_period_id The identifier for the weekday time period associated with the location.
	 * @param array $location An associative array containing location data, including the location ID and optional existing record ID.
	 *
	 * @return void
	 * @throws \Exception If an error occurs while saving the location.
	 */
	private function saveLocation( $time_period_id, $location ) {
		$employeeLocation = isset( $location['id'] )
			? EmployeeWeekdayTimePeriodLocation::findOrNew( $location['id'] )
			: new EmployeeWeekdayTimePeriodLocation();

		$employeeLocation->fill(
			array(
				'weekday_time_period_id' => $time_period_id,
				'location_id'            => $location['location_id'],
			)
		);

		$employeeLocation->save();
	}
}
