<?php
namespace JET_ABAF\Render;

defined( 'ABSPATH' ) || exit; // Exit if accessed directly.

class Price_Breakdown extends Base {

	/**
	 * Render widget wrapper.
	 *
	 * @since 4.1.0
	 *
	 * @param array $breakdown Breakdown payload.
	 *
	 * @return void
	 * @throws \Exception
	 */
	public function render( $breakdown = [] ) {

		$this->setup_post_context( get_the_ID() );

		wp_enqueue_style( 'jet-booking-widget-price-breakdown' );

		printf(
			'<div class="jet-abaf-price-breakdown" data-placeholder="%1$s"><div class="jet-abaf-price-breakdown__content">%2$s</div></div>',
			esc_attr( $this->get_placeholder_content() ),
			$this->get_content( $breakdown ) // phpcs:ignore WordPress.Security.EscapeOutput.OutputNotEscaped
		);

	}

	/**
	 * Get rendered content markup.
	 *
	 * @since 4.1.0
	 *
	 * @param array $breakdown Breakdown payload.
	 *
	 * @return string
	 * @throws \Exception
	 */
	public function get_content( $breakdown = [] ) {

		ob_start();

		$this->render_content( $breakdown );

		return ob_get_clean();

	}

	/**
	 * Render breakdown content.
	 *
	 * @since 4.1.0
	 *
	 * @param array $breakdown Breakdown payload.
	 *
	 * @return void
	 * @throws \Exception
	 */
	public function render_content( $breakdown = [] ) {

		$breakdown = $this->get_breakdown( $breakdown );

		if ( empty( $breakdown ) ) {
			$this->render_placeholder();
			return;
		}

		$this->render_row( $this->get_base_label(), $this->get_amount_display( $breakdown['base'] ?? 0 ), 'base' );

		foreach ( $breakdown as $key => $value ) {
			if ( in_array( $key, [ 'base', 'total' ], true ) ) {
				continue;
			}

			$this->render_row( $this->get_adjustment_label( $key ), $this->get_amount_display( $value, true ), 'adjustment' );
		} ?>

		<div class="jet-abaf-price-breakdown__divider" aria-hidden="true"></div>

		<?php
		$this->render_row( __( 'Subtotal', 'jet-booking' ), $this->get_amount_display( $breakdown['total'] ?? 0 ), 'total' );

	}

	/**
	 * Render a single value row.
	 *
	 * @since 4.1.0
	 *
	 * @param string $label    Row label.
	 * @param string $value    Row value.
	 * @param string $modifier Row modifier.
	 *
	 * @return void
	 */
	protected function render_row( $label, $value, $modifier = '' ) {

		if ( '' === $label && '' === $value ) {
			return;
		}

		$classes = [ 'jet-abaf-price-breakdown__row' ];

		if ( $modifier ) {
			$classes[] = 'jet-abaf-price-breakdown__row--' . sanitize_html_class( $modifier );
		}

		printf(
			'<div class="%1$s"><span class="jet-abaf-price-breakdown__label">%2$s</span><span class="jet-abaf-price-breakdown__value">%3$s</span></div>',
			esc_attr( implode( ' ', $classes ) ),
			esc_html( $label ),
			esc_html( $value )
		);

	}

	/**
	 * Render placeholder content for the empty state.
	 *
	 * @since 4.1.0
	 *
	 * @return void
	 */
	protected function render_placeholder() {

		$message = apply_filters(
			'jet-booking/render/price-breakdown/placeholder-message',
			__( 'Select a date range to see the subtotal breakdown.', 'jet-booking' ),
			$this
		);

		printf( '<div class="jet-abaf-price-breakdown__placeholder" role="status">%s</div>', esc_html( $message ) );

	}

	/**
	 * Get rendered placeholder markup.
	 *
	 * @since 4.1.0
	 *
	 * @return string
	 */
	protected function get_placeholder_content() {

		ob_start();

		$this->render_placeholder();

		return ob_get_clean();

	}

	/**
	 * Resolve breakdown payload for current context.
	 *
	 * @since 4.1.0
	 *
	 * @param array $breakdown Breakdown payload.
	 *
	 * @return array
	 */
	protected function get_breakdown( $breakdown = [] ) {

		if ( filter_var( $this->get_settings( 'is_preview' ), FILTER_VALIDATE_BOOLEAN ) ) {
			return [
				'base'    => 360,
				'weekend' => 20,
				'rate'    => -40,
				'total'   => 340,
			];
		}

		return is_array( $breakdown ) ? $breakdown : [];

	}

	/**
	 * Get base stay label.
	 *
	 * @since 4.1.0
	 *
	 * @return string
	 * @throws \Exception
	 */
	protected function get_base_label() {

		$period_data = $this->get_booking_period_data();
		$duration    = $period_data['duration'] ?? 0;
		$period_type = 'days' === ( $period_data['period_type'] ?? '' ) ? 'days' : 'nights';

		if ( ! $duration ) {
			return __( 'Stay', 'jet-booking' );
		}

		if ( 'days' === $period_type ) {
			/* translators: %d: booking duration in days. */
			return sprintf( _n( 'Stay %d day', 'Stay %d days', $duration, 'jet-booking' ), $duration );
		}

		/* translators: %d: booking duration in nights. */
		return sprintf( _n( 'Stay %d night', 'Stay %d nights', $duration, 'jet-booking' ), $duration );

	}

	/**
	 * Resolve booking period data from current settings.
	 *
	 * @since 4.1.0
	 *
	 * @return array
	 * @throws \Exception
	 */
	protected function get_booking_period_data() {

		if ( filter_var( $this->get_settings( 'is_preview' ), FILTER_VALIDATE_BOOLEAN ) ) {
			return [
				'duration'    => 3,
				'period_type' => 'nights',
			];
		}

		$post_id        = $this->get_settings( 'apartment_id' ) ?: get_the_ID();
		$check_in_date  = $this->get_settings( 'check_in_date' );
		$check_out_date = $this->get_settings( 'check_out_date' );

		if ( ! $post_id || ! $check_in_date || ! $check_out_date ) {
			return [
				'duration'    => 0,
				'period_type' => 'nights',
			];
		}

		$interval = jet_abaf()->tools->get_booking_period_interval( $check_in_date, $check_out_date, $post_id );

		return [
			'duration'    => ! empty( $interval->days ) ? $interval->days : 0,
			'period_type' => jet_abaf()->settings->is_per_nights_booking( $post_id ) ? 'nights' : 'days',
		];

	}

	/**
	 * Get a formatted amount string.
	 *
	 * @since 4.1.0
	 *
	 * @param float|int|string $value  Amount value.
	 * @param bool             $signed Whether to prepend a sign.
	 *
	 * @return string
	 */
	protected function get_amount_display( $value, $signed = false ) {

		$sign = '';

		if ( $signed ) {
			$sign  = 0 > $value ? '-' : ( 0 < $value ? '+' : '' );
			$value = abs( $value );
		}

		return $sign . '$' . $value;

	}

	/**
	 * Resolve adjustment label by key.
	 *
	 * @since 4.1.0
	 *
	 * @param string $key Adjustment key.
	 *
	 * @return string
	 */
	protected function get_adjustment_label( $key ) {
		switch ( $key ) {
			case 'seasonal':
				return __( 'Seasonal pricing', 'jet-booking' );

			case 'weekend':
				return __( 'Weekend pricing', 'jet-booking' );

			case 'rate':
				return __( 'Price rates', 'jet-booking' );

			default:
				return $key ? ucwords( str_replace( [ '-', '_' ], ' ', $key ) ) : __( 'Adjustment', 'jet-booking' );
		}
	}

}
