<?php
namespace SabaiApps\Directories\Component\Booking\Helper;

use SabaiApps\Directories\Application;
use SabaiApps\Directories\Component\Entity\Type\IEntity;
use SabaiApps\Framework\User\AbstractIdentity;
use SabaiApps\Directories\Component\Calendar\Model\Occurrence;

class UtilHelper {

	public function formatDate( Application $application, array $date, array $options = array() ) {
		if ( empty( $date['date'] )
			|| ! isset( $date['start_time'] )
		) {
			$application->logError( 'Invalid date array.' );
			return '';
		}

		$options += array(
			'html'          => true,
			'date_time_sep' => ' ',
			'time_sep'      => ' - ',
		);

		$ret = $application->System_Date( $date['date'], $options['html'] )
			. $application->H( $options['date_time_sep'] )
			. $application->System_Date_time( $date['start_time'], $options['html'] );

		// Append end time if any
		if ( ! empty( $date['end_time'] )
			&& $date['end_time'] > $date['start_time']
		) {
			$ret .= $application->H( $options['time_sep'] ) . $application->System_Date_time( $date['end_time'], $options['html'] );
		}

		return $ret;
	}

	public function renderDate( Application $application, $startDate, $endDate = null, $html = true ) {
		$ret = $application->System_Date_datetime( $startDate, $html );
		if ( isset( $endDate ) ) {
			$ret .= ' - ';
			if ( $application->getPlatform()->getDate( 'Y-m-d', $startDate ) === $application->getPlatform()->getDate( 'Y-m-d', $endDate ) ) {
				$ret .= $application->System_Date( $endDate, $html, $application->getPlatform()->getTimeFormat() );
			} else {
				$ret .= $application->System_Date_datetime( $endDate, $html );
			}
		}
		return $ret;
	}

	public function statuses( Application $application, $status = null ) {
		$statuses = array(
			'pending'          => array(
				'label'     => __( 'Pending', 'directories-pro' ),
				'color'     => 'info',
				'updatable' => array(
					'bookie' => array( 'confirmed', 'rejected' ),
					'booker' => array( 'cancelled' ),
					'admin'  => array( 'confirmed', 'rejected', 'cancelled' ),
				),
			),
			'confirmed'        => array(
				'label'     => __( 'Confirmed', 'directories-pro' ),
				'color'     => 'success',
				'updatable' => array(
					'bookie' => array( 'cancelled' ),
					'booker' => array( 'cancelled' ),
					'admin'  => array( 'cancelled', 'completed' ),
				),
			),
			'rejected'         => array(
				'label'     => __( 'Rejected', 'directories-pro' ),
				'color'     => 'warning',
				'updatable' => false,
			),
			'completed'        => array(
				'label'     => __( 'Completed', 'directories-pro' ),
				'color'     => 'dark',
				'updatable' => false,
			),
			'cancelled'        => array(
				'label'     => __( 'Cancelled', 'directories-pro' ),
				'color'     => 'dark',
				'updatable' => false,
			),
			'system_cancelled' => array(
				'label'     => __( 'System Cancelled', 'directories-pro' ),
				'color'     => 'danger',
				'system'    => true,
				'updatable' => false,
			),
			'failed'           => array(
				'label'     => __( 'Failed', 'directories-pro' ),
				'color'     => 'danger',
				'system'    => true,
				'updatable' => false,
			),
		);
		return isset( $status ) ? ( $statuses[ $status ] ?? null ) : $statuses;
	}

	public function statusLabel( Application $application, $entityOrStatus, $returnArray = false ) {
		if ( $entityOrStatus instanceof IEntity ) {
			$status = $entityOrStatus->getSingleFieldValue( 'booking_status' );
		} else {
			$status = $entityOrStatus;
		}
		if ( empty( $status ) ) {
			$status = 'pending';
		}
		if ( ! $status = $this->statuses( $application, $status ) ) {
			return;
		}

		if ( $returnArray ) {
			return array(
				'label' => $status['label'],
				'color' => array( 'name' => $status['color'] ),
			);
		}

		return $this->statusHtmlLabel( $application, $status['label'], $status['color'] );
	}

	public function canChangeStatus( Application $application, IEntity $booking, $status, $role = 'booker', ?AbstractIdentity $identity = null ) {
		if ( ! isset( $identity ) ) {
			$identity = $application->getUser()->getIdentity();
		}
		switch ( $role ) {
			case 'bookie':
				if ( ! $parent_entity = $application->Entity_ParentEntity( $booking ) ) {
					$application->logError( 'Could not fetch parent entity for booking ID ' . $booking->getId() . '.' );
					return false;
				}
				if ( ! $application->Entity_IsAuthor( $parent_entity, $identity ) ) {
					return false;
				}
				break;
			case 'admin':
				if ( ! $application->IsAdministrator( $identity ) ) {
					return false;
				}
				break;
			case 'booker':
				if ( ! $application->Entity_IsAuthor( $booking, $identity ) ) {
					return false;
				}
				break;
			default:
				if ( $application->IsAdministrator( $identity ) ) {
					$role = 'admin';
					break;
				}
				if ( $application->Entity_IsAuthor( $booking, $identity ) ) {
					$role = 'booker';
					break;
				}
				return false;
		}
		if ( ! $current_status = $booking->getSingleFieldValue( 'booking_status' ) ) {
			$current_status = 'pending';
		}
		if ( ( ! $current_status_info = $this->statuses( $application, $current_status ) )
			|| empty( $current_status_info['updatable'][ $role ] )
		) {
			return false;
		}

		$statuses_to_check = is_array( $status ) ? $status : array( $status );
		foreach ( $statuses_to_check as $i => $s ) {
			if ( ! in_array( $s, $current_status_info['updatable'][ $role ], true ) ) {
				unset( $statuses_to_check[ $i ] );
			}
		}
		return empty( $statuses_to_check ) ? false : $statuses_to_check;
	}

	public function spacesAvailable( Application $application, Occurrence $occurrence, $addBookedSpaces = 0 ) {
		if ( empty( $occurrence->slot_data_snapshot['booking_max_spaces'] ) ) {
			return 0;
		}

		$spaces_available  = $occurrence->data['booking_spaces_available'] ?? $occurrence->slot_data_snapshot['booking_max_spaces'];
		$spaces_available += $addBookedSpaces;
		if ( $spaces_available > $occurrence->slot_data_snapshot['booking_max_spaces'] ) {
			$spaces_available = $occurrence->slot_data_snapshot['booking_max_spaces'];
		}
		return ( $spaces_available = intval( $spaces_available ) ) ? $spaces_available : 0;
	}

	public function statusHtmlLabel( Application $application, $label, $color ) {
		return sprintf(
			'<span class="%1$sbadge %1$sbg-%2$s" style="font-size:14px;">%3$s</span>',
			DRTS_BS_PREFIX,
			$color,
			$application->H( $label )
		);
	}

	public function updateOccurrenceAvailableSpaces( Application $application, $booking, $decrease = false, ?Occurrence $occurrence = null ) {
		if ( ! isset( $occurrence ) ) {
			if ( ( ! $occurrence_hash = $booking->getSingleFieldValue( 'booking_info', 'occurrence_hash' ) )
				|| ( ! $occurrence = $application->getModel( 'Occurrence', 'Calendar' )->hash_is( $occurrence_hash )->fetchOne() )
			) {
				$application->logError( 'Invalid occurrence hash "' . $occurrence_hash . '" for booking ID ' . $booking->getId() . '.' );
				return;
			}
		} elseif ( $booking->getSingleFieldValue( 'booking_info', 'occurrence_hash' ) !== $occurrence->hash ) {
				$application->logError( 'Occurrence hash (' . $occurrence->hash . ') mismatch for booking ID ' . $booking->getId() . ' (' . $booking->getSingleFieldValue( 'booking_info', 'occurrence_hash' ) . ').' );
				return;
		}

		$occurrence_data = $occurrence->data;
		if ( ! isset( $occurrence_data['booking_spaces_available'] ) ) {
			$occurrence_data['booking_spaces_available'] = $occurrence->slot_data_snapshot['booking_max_spaces'];
		}
		$spacesChange = $booking->getSingleFieldValue( 'booking_spaces' );
		if ( $decrease ) {
			$spacesChange *= -1;
		}
		$occurrence_data['booking_spaces_available'] += $spacesChange;
		if ( $occurrence_data['booking_spaces_available'] < 0 ) {
			$application->logError( 'Available booking spaces for occurrence ("' . $occurrence->hash . '") went below zero.' );
			$occurrence_data['booking_spaces_available'] = 0;
		} elseif ( $occurrence_data['booking_spaces_available'] > $occurrence->slot_data_snapshot['booking_max_spaces'] ) {
			$application->logError( 'Available booking spaces for occurrence ("' . $occurrence->hash . '") exceeded maximum allowed spaces.' );
			$occurrence_data['booking_spaces_available'] = $occurrence->slot_data_snapshot['booking_max_spaces'];
		}
		$occurrence->data = $occurrence_data;
		$occurrence->commit();
	}
}
