<?php
/**
 * RadiusBooking API Route Registrar
 *
 * This class is responsible for registering API routes dynamically with the WordPress REST API.
 * It supports CRUD operations and allows for middleware to be applied globally or per route.
 *
 * @package RadiusTheme\RadiusBooking\Core\Api\Routes
 */

namespace RadiusTheme\RadiusBooking\Repositories;

if ( ! defined( 'ABSPATH' ) ) {
	exit; // Exit if accessed directly
}
use RadiusTheme\RadiusBooking\Abstracts\BaseRepository;
use RadiusTheme\RadiusBooking\Models\Category;
use RadiusTheme\RadiusBooking\Models\EmployeeService;
use RadiusTheme\RadiusBooking\Models\Service;

/**
 * Repository class for managing Service entities.
 */
class ServiceRepository extends BaseRepository {

	/**
	 * The model class managed by this repository.
	 *
	 * @var string
	 */
	protected string $model = Service::class;

	/**
	 * Retrieve all active services.
	 *
	 * @return array An array of active Service models.
	 */
	public function active(): array {
		return Service::where( 'active', true )->get();
	}

	/**
	 * Retrieves a list of active services for a given category.
	 *
	 * @param int $categoryId The ID of the category whose services are to be retrieved.
	 * @param string $status The status of the services to retrieve.
	 *
	 * @return array An array of active services under the specified category.
	 */
	public function getCategoryServices( int $categoryId, string $status= 'active' ): array {
		return Category::where( 'id', $categoryId )
			->where( 'status', '=', $status )
			->get();
	}

	/**
	 * Retrieves the assigned service for a specific user based on the given service ID and user ID.
	 *
	 * @param int|string $serviceId The ID of the service to retrieve.
	 * @param int|string $userId The ID of the user associated with the service.
	 *
	 * @return mixed Returns the first matching record from the EmployeeService or null if none is found.
	 */
	public function getAssignServices( $serviceId, $userId ) {
		return EmployeeService::where( 'user_id', $userId )
			->where( 'service_id', '=', $serviceId )
			->first();
	}

	public function getServicesEmployees( $service_id ) {
		return EmployeeService::where( 'service_id', $service_id )->get();
	}

	public function getServicesEmployeesIds( $service_id ) {
		$employees = $this->getServicesEmployees( $service_id );

		if ( empty( $employees ) ) {
			return array();
		}

		// Convert collection to array if needed
		if ( is_object( $employees ) && method_exists( $employees, 'toArray' ) ) {
			$employees = $employees->toArray();
		}

		return array_map(
			function ( $employee ) {
				if ( is_array( $employee ) ) {
					  return $employee['user_id'] ?? null;
				}
				return $employee->user_id ?? null;
			},
			(array) $employees
		);
	}

	public function getExistingEmployeesIds( $service_id ) {
		$employees = EmployeeService::where( 'service_id', $service_id )
			->get();
		foreach ( $employees as $employee ) {
			$employee_ids[] = array(
				'id' => $employee->id,
				'user_id' => $employee->user_id,
				'service_id' => $employee->service_id,
			);
		}
		return $employee_ids ?? array();
	}

	public function existsServiceAndEmployee( $service_id, $user_id ) {
		return EmployeeService::where( 'service_id', $service_id )->where( 'user_id', $user_id )->exists();
	}

	public function deleteEmployeeFromService( $id, $userId ) {
		$employeeService = EmployeeService::where( 'service_id', $id )
										  ->where( 'user_id', $userId )
										  ->first();

		$employee = EmployeeService::find( $employeeService->id );
		if ( $employee ) {
			$employee->delete();
		}
	}

	/**
	 * Apply a price delta to every employee row attached to a service.
	 *
	 * Preserves each employee's relative override: if their price was
	 * service_price + 10, after the delta it remains new_service_price + 10.
	 * Negative results are clamped to 0.
	 *
	 * @param int   $serviceId Service whose employee rows to adjust.
	 * @param float $delta     New service price minus old service price.
	 *
	 * @return int Number of employee rows updated.
	 */
	public function applyPriceDeltaToEmployees( int $serviceId, float $delta ): int {
		if ( 0.0 === (float) $delta ) {
			return 0;
		}

		global $wpdb;
		$table = radius_table_prefix() . 'employees_services';

		// phpcs:ignore WordPress.DB.PreparedSQL.InterpolatedNotPrepared
		return (int) $wpdb->query(
			$wpdb->prepare(
				"UPDATE {$table} SET price = GREATEST(0, price + %f) WHERE service_id = %d",
				$delta,
				$serviceId
			)
		);
	}
}
