<?php
/** 
 * @package     VikRestaurants
 * @subpackage  core
 * @author      E4J s.r.l.
 * @copyright   Copyright (C) 2023 E4J s.r.l. All Rights Reserved.
 * @license     http://www.gnu.org/licenses/gpl-2.0.html GNU/GPL
 * @link        https://vikwp.com
 */

// No direct access
defined('ABSPATH') or die('No script kiddies please!');

use E4J\VikRestaurants\TakeAway\Cart;
use E4J\VikRestaurants\TakeAway\Cart\Item;

/**
 * VikRestaurants take-away upselling model.
 *
 * @since 1.11
 */
class VikRestaurantsModelUpselling extends JModelVRE
{
	/**
	 * Returns the items eligible for upselling according to the cart elements.
	 * 
	 * @param   Cart|Item[]|int[]  $items    The cart items or the cart itself.
	 * @param   array              $options  A configuration array.
	 * 
	 * @return  array  The eligible menus and items.
	 */
	public function getEligibleItems($items, array $options = [])
	{
		$config = VREFactory::getConfig();

		if ($items instanceof Cart)
		{
			// extract check-in information from cart instance
			$options['date'] = $options['date'] ?? date($config->get('dateformat'), $items->getCheckinTimestamp());
			$options['hourmin'] = $options['hourmin'] ?? $items->getCheckinTime();

			// load items from cart
			$items = $items->getItems();
		}

		// properly map the items
		$items = array_map(function($item) {
			if ($item instanceof Item)
			{
				// extract ID from cart item instance
				$item = $item->getItemID();
			}

			return (int) $item;
		}, $items);

		// define default settings
		$options['since'] = $options['since'] ?? $config->get('upselling_training_since');
		$options['topn'] = $options['topn'] ?? $config->get('upselling_topn');
		$options['weights'] = $options['weights'] ?? $config->getArray('upselling_weights');

		// create storage and train on the fly
		$databaseRepository = new E4J\VikRestaurants\Upselling\Statistics\DatabaseRepository(['since' => $options['since'] ?? null]);
		$databaseRepository->train();

		// create score calculator instance, based on the previously created repo
		$scoreCalculator = new E4J\VikRestaurants\Upselling\Score\ConfidenceLiftCalculator($databaseRepository, $options['weights'] ?? []);

		// create upselling engine
		$upsellingEngine = new E4J\VikRestaurants\Upselling\UpsellingEngine($scoreCalculator, [
			'date' => $options['date'] ?? null,
			'hourmin' => $options['hourmin'] ?? null,
		]);

		// get suggestions for the items in cart
		$hints = $upsellingEngine->getSuggestions($items, $options['topn'] ?: 3);

		if (!$hints)
		{
			return [];
		}

		$menuScoreLookup = $itemScoreLookup = [];

		foreach ($hints as $hint)
		{
			// take only the highest score obtained for the products of this menu
			$menuScoreLookup[$hint->idMenu] = max($hint->score, $menuScoreLookup[$hint->idMenu] ?? 0);
			$itemScoreLookup[$hint->id] = $hint->score;
		}

		// load item details
		$menus = JModelVRE::getInstance('takeaway')->getItems([
			'strict' => true,
			'date' => $options['date'] ?? null,
			'products' => array_map(function($hint) {
				return $hint->id;
			}, $hints),
		]);

		// sort menus by descending score
		usort($menus, function($a, $b) use ($menuScoreLookup) {
			return $menuScoreLookup[$b->id] <=> $menuScoreLookup[$a->id];
		});

		foreach ($menus as $menu)
		{
			// reset product keys
			$menu->products = array_values($menu->products);

			foreach ($menu->products as $product)
			{
				// reset option keys
				$product->options = array_values($product->options);
				// inject obtained score
				$product->score = $itemScoreLookup[$product->id] ?? 0;
			}
		}

		return array_values($menus);
	}
}
