<?php

final class SLN_Wrapper_Booking_Services {

	private $items = array();

	/**
	 * SLN_Wrapper_Booking_Services constructor.
	 *
	 * @param $data
	 */
	public function __construct( $data ) {
		if(!empty($data)){
			foreach ($data as $key =>$item) {
				$this->items[] = new SLN_Wrapper_Booking_Service($item);
			}
		}
	}

	/**
	 * @return SLN_Wrapper_Booking_Service[]
	 */
	public function getItems() {
		return empty($this->items) ? array() : $this->items;
	}

	/**
	 * @return int
	 */
	public function getCount() {
		return count($this->getItems());
	}

	/**
	 * @return null|SLN_Wrapper_Booking_Service
	 */
	public function getFirstItem() {
		$items = $this->getItems();
		return empty($items) ? null : reset($items);
	}

	/**
	 * @param int $serviceId
	 *
	 * @return false|SLN_Wrapper_Booking_Service
	 */
	public function findByService($serviceId) {
		foreach($this->getItems() as $bookingService) {
			if ($serviceId == $bookingService->getService()->getId()) {
				return $bookingService;
			}
		}
		return false;
	}

	/**
	 * @param SLN_Wrapper_Booking_Service $bookingService
	 *
	 * @return bool|int
	 */
	public function getPosInQueue(SLN_Wrapper_Booking_Service $bookingService) {
		$pos = array_search($bookingService, $this->items);

		return ($pos === false ? $pos : $pos + 1);
	}

	public function isLast(SLN_Wrapper_Booking_Service $bookingService) {
		return count($this->items) && $this->items[count($this->items) - 1] === $bookingService;
	}

	public function toArrayRecursive() {
		$ret = array();
		if(!empty($this->items)){
			foreach ($this->items as $item) {
				/** @var SLN_Wrapper_Booking_Service $item */
				$ret[] = $item->toArray();
			}
		}

		return $ret;
	}

	/**
	 * @param array $data   array($service_id => $attendant_id) or array($service_id => array('attendant' => $attendant_id, 'price' => float, 'duration' => 'H:i' ))
	 * @param SLN_DateTime $startsAt
	 * @param int $offset   minutes
	 *
	 * @return SLN_Wrapper_Booking_Services
	 */
	public static function build($data, SLN_DateTime $startsAt, $offset = 0, $serviceCount = array(), $resources = array()) {
		$startsAtClone = clone $startsAt;
		$services       = array();
		$settings       = SLN_Plugin::getInstance()->getSettings();
		$sequentialOnly = $settings->isDoNotNestSameBookingServicesEnabled();
		$nestedBookings = $settings->isNestedBookingsEnabled();

		foreach ( $data as $i => $item ) {

            $sId      = null;
			$atId     = null;
			$price    = null;
			$duration = null;
			$break    = null;
			$break_duration_data = null;
			$resource = null;

			if (is_array($item) && array_intersect(array_keys($item), array('service', 'attendant', 'price', 'duration', 'break_duration', 'break_duration_data', 'resource'))) {
                if (isset($item['service'])) {
                    $sId = intval($item['service']);
                }
			if (isset($item['attendant'])) {
				if(!is_array($item['attendant'])){
					// SMART AVAILABILITY: Preserve false marker for auto-assignment
					$atId = ($item['attendant'] === false) ? false : intval($item['attendant']);
				}else{
					$atId = array_map('intval', $item['attendant']);
				}
			}
				if (isset($item['price'])) {
					$price = floatval($item['price']);
				}
				if (isset($item['duration'])) {
					$duration = $item['duration'];
				}
				if (isset($item['break_duration'])) {
					$break = $item['break_duration'];
				}
				if (isset($item['break_duration_data'])) {
					$break_duration_data = $item['break_duration_data'];
				}
				if (isset($item['resource'])) {
					$resource = $item['resource'];
				}
			} else {
                $sId  = intval($i);
				if(!is_array($item)){
					// SMART AVAILABILITY: Preserve false marker for auto-assignment
					$atId = ($item === false) ? false : intval($item);
				}else{
					$atId = array_map('intval', $item);
				}
			}

            $service = SLN_Plugin::getInstance()->createService($sId);
            $service = apply_filters('sln.booking_services.buildService', $service);

			if (is_null($price)) {
                $price = $service->getVariablePriceEnabled() && $service->getVariablePrice($atId) !== '' ? $service->getVariablePrice($atId) : $service->getPrice();
				$builder = SLN_Plugin::getInstance()->getBookingBuilder();
				if ( $builder ) {
					$price = apply_filters( 'sln.booking_builder.service_price', $price, $service, $atId, $builder );
				}
			}

			if (empty($duration)) {
				$duration = $service->getDuration()->format('H:i');
                $ret = SLN_Func::getMinutesFromDuration($duration)*60;
                $duration = $ret;
                $duration = (new SLN_DateTime('@'.$duration))->format('H:i');
			}

			if (empty($break)) {
				$break = $service->getBreakDuration()->format('H:i');
			}

			if (empty($break_duration_data)) {
				$break_duration_data = $service->getBreakDurationData();
			}

			if (empty($resource) && isset($resources[$service->getId()])) {
                $resource = $resources[$service->getId()];
            }

			$parallelExec = $service->isExecutionParalleled();

            $rawCount = isset($serviceCount[$service->getId()]) ? $serviceCount[$service->getId()] : 1;
            $c        = (int) $rawCount;
            $count    = $c > 0 ? $c : 1;

			$services[$i] = array(
				'service'	=> $sId,
				'attendant'	=> $atId,
				'start_date'	=> $parallelExec ? $startsAt->format('Y-m-d') : $startsAtClone->format('Y-m-d'),
                'start_time'	=> $parallelExec ? $startsAt->format('H:i') : $startsAtClone->format('H:i'),
				'duration'	=> $duration,
				'break_duration'   => $break,
				'break_duration_data'   => $break_duration_data,
				'price'		=> $price,
				'exec_order'	=> $service->getExecOrder(),
				'parallel_exec' => $parallelExec,
                'count' => $count,
                'resource'      => $resource,
			);
			if ( ! $parallelExec ) {
				$breakMinutes = SLN_Func::getMinutesFromDuration($break);
				$breakFrom    = isset($break_duration_data['from']) ? intval($break_duration_data['from']) : 0;

				if (
					! $sequentialOnly
					&& $breakMinutes > 0 && $breakFrom > 0 && isset($break_duration_data['to']) && $break_duration_data['to'] > $breakFrom
				) {
					// Custom break position: next service starts at the break window (stylist is free during break).
					$minutes = $breakFrom + $offset;
				} else {
					// Standard case: advance by full work duration + break duration.
					$minutes = SLN_Func::getMinutesFromDuration($duration) + $breakMinutes + $offset;
				}
				$startsAtClone->modify( '+' . $minutes . ' minutes' );
			}
		}
		//usort($services, array('SLN_Repository_ServiceRepository', 'serviceCmp'));
		$ret = new SLN_Wrapper_Booking_Services($services);

		return $ret;
	}

}
