<?php
/**
 * Factory for article availabilities, when dealing with API data.
 *
 * @package flo-sync
 */

namespace NMFS\Sync\Items\Article_Availabilities;

use NMFS\Sync\Items\Article_Availabilities\Models\Article_Availability_Model;
use NMFS\Sync\Items\Article_Availabilities\Models\Items\Item_Model;
use NMFS\Sync\Items\Article_Availabilities\Models\Items\Item_Type_Enum;
use NMFS\Sync\Items\Article_Availabilities\Models\Schedules\Day_Of_Week_Schedule_Model;
use NMFS\Sync\Items\Article_Availabilities\Models\Schedules\Periods\Day_Time_Period_Model;
use NMFS\Sync\Items\Article_Availabilities\Models\Schedules\Schedule_Interface;

defined( 'ABSPATH' ) || exit;

/**
 * Class Factory
 */
class Factory_API {

	/**
	 * Create an article availability from API data.
	 *
	 * @param array $api_data The API data.
	 *
	 * @return Article_Availability_Model
	 */
	public static function create_availability_from_api( array $api_data ): Article_Availability_Model {
		$availability = new Article_Availability_Model();

		$availability->hub_id  = $api_data['Id'];
		$availability->name    = $api_data['Name'];
		$availability->enabled = $api_data['Enabled'];

		$availability->schedules = self::create_schedules_from_availability_time( $api_data['AvailabilityTime'] );

		$availability->items = array_map(
			fn( $item ) => self::create_item_from_api( $item ),
			$api_data['AvailableArticles']
		);

		return $availability;
	}

	/**
	 * Create article availability schedules from API data.
	 *
	 * @param array $availability_time The API data.
	 *
	 * @return Schedule_Interface[]
	 */
	private static function create_schedules_from_availability_time( array $availability_time ): array {
		return array_merge(
			array_map(
				fn( $day ) => self::create_day_of_week_time_availability_from_api( $day ),
				$availability_time['DayOfWeekAvailabilities']
			),
			// TODO: Add MonthAvailability and DateAvailability when implemented in Hub.
		);
	}

	/**
	 * Creates a Day_Of_Week_Time_Availability_Model object from API day of week time availability data.
	 *
	 * @param array $day The API day of week time availability data.
	 *
	 * @return Day_Of_Week_Schedule_Model The created Day_Of_Week_Time_Availability_Model object.
	 */
	private static function create_day_of_week_time_availability_from_api( array $day ): Day_Of_Week_Schedule_Model {
		$day_of_week_time_availability               = new Day_Of_Week_Schedule_Model();
		$day_of_week_time_availability->day_of_week  = $day['Day'];
		$day_of_week_time_availability->time_periods = array_map(
			fn( $time ) => self::create_time_period_from_api( $time ),
			$day['AvailabilityTimes']
		);

		return $day_of_week_time_availability;
	}

	/**
	 * Creates a Day_Time_Period_Model object from an array of time.
	 *
	 * @param array $time An array containing the start time and end time information.
	 *
	 * @return Day_Time_Period_Model The created Day_Time_Period_Model object.
	 */
	private static function create_time_period_from_api( array $time ): Day_Time_Period_Model {
		$time_period                    = new Day_Time_Period_Model();
		$time_period->start_time_hour   = $time['StartTime']['Hour'];
		$time_period->start_time_minute = $time['StartTime']['Minute'];
		$time_period->end_time_hour     = $time['EndTime']['Hour'];
		$time_period->end_time_minute   = $time['EndTime']['Minute'];

		return $time_period;
	}

	/**
	 * Creates an Available_Articles_Item_Model object from an array of item.
	 *
	 * @param array $item An array containing the item information.
	 *
	 * @return Item_Model The created Available_Articles_Item_Model object.
	 */
	private static function create_item_from_api( array $item ): Item_Model {
		$available_item = new Item_Model();

		switch ( $item['AvailablePer'] ) {
			case 'Article':
				$available_item->type = Item_Type_Enum::Article;
				$available_item->id   = $item['ArticleNumber'];
				break;
			case 'ArticleGroup':
				$available_item->type = Item_Type_Enum::ArticleGroup;
				$available_item->id   = $item['ArticleGroupId'];
				break;
		}

		return $available_item;
	}
}
