<?php
/**
 * MeetingTypeResource
 *
 * Transforms MeetingType model data into API response format.
 *
 * @package RadiusTheme\RadiusBooking\Resources
 * @since   1.2.0
 */

namespace RadiusTheme\RadiusBooking\Resources;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

use RadiusTheme\RadiusBooking\Abstracts\BaseResource;
use RadiusTheme\RadiusBooking\Core\Container\Container;
use RadiusTheme\RadiusBooking\Helpers\SettingsHelper;
use RadiusTheme\RadiusBooking\Models\MeetingType;
use RadiusTheme\RadiusBooking\Repositories\MeetingTypeRepository;

/**
 * Class MeetingTypeResource
 */
class MeetingTypeResource extends BaseResource {

	/**
	 * Transform a meeting type into an API-friendly array.
	 *
	 * @param mixed $meeting_type The meeting type model or object.
	 *
	 * @return array
	 */
	public function transform( $meeting_type ): array {
		$repo         = new MeetingTypeRepository();
		$availability = $repo->getAllAvailability( $meeting_type->id );
		$overrides    = $repo->getDateOverrides( $meeting_type->id );

		return array(
			'id'                    => $meeting_type->id,
			'employee_id'           => $meeting_type->employee_id,
			'employee_name'         => $this->getEmployeeName( $meeting_type->employee_id ),
			'employee_image'        => $this->getEmployeeImage( $meeting_type->employee_id ),
			'name'                  => $meeting_type->name,
			'description'           => $meeting_type->description,
			'slug'                  => $meeting_type->slug,
			'duration'              => $meeting_type->duration,
			'buffer_before'         => $meeting_type->buffer_before,
			'buffer_after'          => $meeting_type->buffer_after,
			'price'                 => $meeting_type->price,
			'color'                 => $meeting_type->color,
			'location_type'         => $meeting_type->location_type,
			'location_details'      => $meeting_type->location_details,
			'is_active'             => $meeting_type->is_active,
			'requires_confirmation' => $meeting_type->requires_confirmation,
			'max_bookings_per_day'  => $meeting_type->max_bookings_per_day,
			'min_notice_minutes'    => $meeting_type->min_notice_minutes,
			'max_advance_days'      => $meeting_type->max_advance_days,
			'settings'              => $this->resolveSettings( $meeting_type ) ?: new \stdClass(),
			'picture_full_path'     => $meeting_type->picture_full_path,
			'picture_thumb_path'    => $meeting_type->picture_thumb_path,
			'availability'          => $this->formatAvailability( $availability ),
			'date_overrides'        => $this->formatDateOverrides( $overrides ),
			'shareable_url'         => $this->getShareableUrl( $meeting_type ),
			'created_at'            => $meeting_type->created_at ?? null,
			'updated_at'            => $meeting_type->updated_at ?? null,
			'currency_symbol'       => function_exists( 'get_rtrb_currency_symbol' ) ? get_rtrb_currency_symbol() : '$',
			'currency'              => function_exists( 'get_rtrb_currency' ) ? get_rtrb_currency() : 'USD',
			'payment_methods'       => $this->getAvailablePaymentMethods( $meeting_type ),
		);
	}

	/**
	 * Get the employee display name.
	 *
	 * @param int $employee_id WordPress user ID.
	 *
	 * @return string|null
	 */
	private function getEmployeeName( $employee_id ): ?string {
		if ( ! $employee_id ) {
			return null;
		}
		$user = get_userdata( $employee_id );
		return $user ? $user->display_name : null;
	}

	/**
	 * Get the employee profile image URL.
	 *
	 * @param int $employee_id WordPress user ID.
	 * @return string
	 */
	private function getEmployeeImage( $employee_id ): string {
		if ( ! $employee_id ) {
			return '';
		}
		$repo = Container::resolve( \RadiusTheme\RadiusBooking\Repositories\UserProfileRepository::class );
		if ( $repo->exists( $employee_id ) ) {
			$profile = $repo->find( $employee_id );
			return $profile->getImageUrl() ?: '';
		}
		return '';
	}

	/**
	 * Format availability data for the API response.
	 *
	 * Groups flat DB rows (one per time window) into per-day objects
	 * with a time_windows array, matching the frontend component format.
	 *
	 * @param array $availability Raw availability records.
	 *
	 * @return array
	 */
	private function formatAvailability( array $availability ): array {
		$grouped = array();

		foreach ( $availability as $slot ) {
			$day        = $slot->day_of_week ?? ( $slot['day_of_week'] ?? null );
			$start      = $slot->start_time ?? ( $slot['start_time'] ?? null );
			$end        = $slot->end_time ?? ( $slot['end_time'] ?? null );
			$is_enabled = $slot->is_enabled ?? ( $slot['is_enabled'] ?? true );

			if ( null === $day ) {
				continue;
			}

			$day = (int) $day;

			if ( ! isset( $grouped[ $day ] ) ) {
				$grouped[ $day ] = array(
					'day_of_week'  => $day,
					'is_enabled'   => (bool) $is_enabled,
					'start_time'   => $start,
					'end_time'     => $end,
					'time_windows' => array(),
				);
			}

			$grouped[ $day ]['time_windows'][] = array(
				'start_time' => $start,
				'end_time'   => $end,
			);
		}

		return array_values( $grouped );
	}

	/**
	 * Format date overrides for the API response.
	 *
	 * @param array $overrides Raw override records.
	 *
	 * @return array
	 */
	private function formatDateOverrides( array $overrides ): array {
		return array_map(
			function ( $override ) {
				$is_unavailable = $override->is_unavailable ?? ( $override['is_unavailable'] ?? false );

				return array(
					'id'              => $override->id ?? ( $override['id'] ?? null ),
					'override_date'   => $override->override_date ?? ( $override['override_date'] ?? null ),
					'is_unavailable'  => (bool) $is_unavailable,
					'start_time'      => $override->start_time ?? ( $override['start_time'] ?? null ),
					'end_time'        => $override->end_time ?? ( $override['end_time'] ?? null ),
				);
			},
			$overrides
		);
	}

	/**
	 * Safely resolve settings from a MeetingType model or stdClass.
	 *
	 * @param mixed $meeting_type Model instance or stdClass from query.
	 *
	 * @return array|object Settings array or empty stdClass for JSON.
	 */
	private function resolveSettings( $meeting_type ): array {
		// If it's a proper MeetingType model, use the method.
		if ( $meeting_type instanceof MeetingType ) {
			return $meeting_type->get_settings();
		}

		// Raw stdClass from DB query — decode settings manually.
		$raw = $meeting_type->settings ?? null;
		if ( is_array( $raw ) ) {
			return $raw;
		}
		if ( is_string( $raw ) && ! empty( $raw ) ) {
			$decoded = json_decode( $raw, true );
			if ( is_array( $decoded ) ) {
				return $decoded;
			}
			$unserialized = maybe_unserialize( $raw );
			if ( is_array( $unserialized ) ) {
				return $unserialized;
			}
		}
		return array();
	}

	/**
	 * Get available payment methods for a meeting type.
	 *
	 * @param mixed $meeting_type The meeting type model.
	 *
	 * @return array
	 */
	private function getAvailablePaymentMethods( $meeting_type ): array {
		$settings        = $this->resolveSettings( $meeting_type );
		$mt_methods      = $settings['paymentMethods'] ?? array();
		$global_payments = SettingsHelper::get_setting( 'payment' );
		$methods         = array();

		// Offline is always available unless explicitly disabled.
		if ( $mt_methods['offline'] ?? true ) {
			$methods[] = 'offline';
		}

		// Stripe — requires global config + meeting type toggle.
		if ( ! empty( $mt_methods['stripe'] ) && ! empty( $global_payments['stripe']['enabled'] ) ) {
			$methods[] = 'stripe';
		}

		// PayPal — requires global config + meeting type toggle.
		if ( ! empty( $mt_methods['paypal'] ) && ! empty( $global_payments['paypal']['enabled'] ) ) {
			$methods[] = 'paypal';
		}

		return $methods;
	}

	/**
	 * Generate the public shareable booking URL.
	 *
	 * @param mixed $meeting_type The meeting type model.
	 *
	 * @return string
	 */
	private function getShareableUrl( $meeting_type ): string {
		return rtrb_booking_page_url( 'meetingBookingPage', 'meeting', $meeting_type->slug );
	}
}
