<?php
/**
 * BookiFlex Cart Extension
 *
 * @package    BookiFlex
 * @subpackage Cart
 * @author     BookiFlex
 * @copyright  Copyright (c) 2025 BookiFlex
 * @license    GPL-2.0-or-later
 *
 * @link       https://bookiflex.com
 */

declare(strict_types=1);

namespace BookiFlex\Extensions\Cart\Contract;

use BookiFlex\Extensions\Cart\DTO\CartExtraContext;
use BookiFlex\Extensions\Cart\DTO\CartExtraSnapshot;

defined( 'ABSPATH' ) || exit;

/**
 * Contract for the provider of additional services for the shopping cart.
 * *
 * * The shopping cart is unaware of the extras domain model (where they live, how prices are calculated,
 * * what their rules are). The extension that owns the extras domain implements this
 * * interface and registers the implementation in the DI.
 */
interface CartExtraProviderInterface
{
    /**
     * Returns a generic snapshot of the extra service or null if it cannot be added
     * (e.g. inactive, hidden, missing).
     */
    public function findExtra(int $extraId): ?CartExtraSnapshot;

    /**
     * Calculates the final price (in minor units) for the given extra in the given
     * booking context. The result represents the total for all requested units
     * (context->quantity is taken into account for PER_USE charging rates).
     */
    public function calculatePrice(CartExtraSnapshot $extra, CartExtraContext $context): int;

    /**
     * Calculates the price for ONE unit of the extra in the given booking context
     * (minor units). Quantity is always treated as 1 — this is the per-unit cost
     * that CartItem uses as its unitPrice before multiplying by CartItem::quantity.
     */
    public function calculateUnitPrice(CartExtraSnapshot $extra, CartExtraContext $context): int;

    /**
     * Domain-level validation (e.g. PER_BOOKING extras cannot be added via cart,
     * quantity above maxPerUnit, etc.).
     *
     * @return array<string, string> code => message; empty array means valid
     */
    public function validate(CartExtraSnapshot $extra, int $quantity): array;

    /**
     * Returns the ids of extras that are bundled into the given rate plan for
     * the given accommodation type. Empty array means there are no included
     * extras (or the rate plan / accommodation type cannot be resolved).
     *
     * @return int[]
     */
    public function getIncludedExtraIds(int $ratePlanId, int $accommodationTypeId): array;
}
