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

declare(strict_types=1);

namespace BookiFlex\Core\Service\Reservation;

use BookiFlex\Core\Contract\AccommodationType\AccommodationTypeRepositoryInterface;
use BookiFlex\Core\Contract\Adjustment\AdjustmentStrategy;
use BookiFlex\Core\Contract\Payment\PaymentAllocationInterface;
use BookiFlex\Core\Contract\Payment\PaymentAllocationProviderInterface;
use BookiFlex\Core\Contract\RatePlan\RatePlanRepositoryInterface;
use BookiFlex\Core\Contract\Reservation\ReservationRepositoryInterface;
use BookiFlex\Core\Exception\MoneyCalculationException;
use BookiFlex\Core\Model\AccommodationType\Accommodation\AccommodationType;
use BookiFlex\Core\Model\Reservation\Reservation;
use BookiFlex\Core\Contract\Taxation\TaxRuleProviderInterface;
use Symfony\Component\Uid\UuidV4;

defined( 'ABSPATH' ) || exit;

class ReservationDetails
{
    public function __construct(
        private readonly ReservationRepositoryInterface $reservationRepository,
        private readonly RatePlanRepositoryInterface $ratePlanRepository,
        private readonly AccommodationTypeRepositoryInterface $accommodationTypeRepository,
        private readonly ?PaymentAllocationProviderInterface $paymentAllocationProvider = null,
    ) {
    }

    /**
     * Return all reservations linked in one group
     *
     * @param int|string $id id or sid
     * @return Reservation[]
     */
    public function getReservationGroup(int|string $id): array
    {
        $mainReservation = null;
        if (is_numeric($id)) {
            $mainReservation = $this->reservationRepository->findByPK($id);
        } elseif (UuidV4::isValid($id)) {
            $mainReservation = $this->reservationRepository->findOne(['sid' => $id]);
        }

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

        if ($group = $mainReservation->getGroup()) {
            $reservations = $group->getReservations();
        } else {
            $reservations = [$mainReservation];
        }

        return $reservations;
    }

    /**
     * Return set of group reservations
     *
     * @param string $sid sid of any reservation of group
     * @return Reservation[]
     */
    public function findReservationsGroup(string $sid): array
    {
        /** @var Reservation|null $mainReservation */
        $mainReservation = $this->reservationRepository->findOne(['sid' => $sid]);
        if (!$mainReservation) {
            return [];
        }

        if ($group = $mainReservation->getGroup()) {
            $reservations = $group->getReservations();
        } else {
            $reservations = [$mainReservation];
        }

        return $reservations;
    }

    /**
     * @param Reservation[] $reservations
     * @return PaymentAllocationInterface[]
     */
    public function getPaymentAllocations(array $reservations): array
    {
        return ($this->paymentAllocationProvider)
            ? $this->paymentAllocationProvider->getPaymentAllocations($reservations)
            : [];
    }

    /**
     * @return Array<string, string> list of code => name
     */
    public function getRatePlanNames(): array
    {
        $result = [];

        $ratePlans = $this->ratePlanRepository->findAll();
        foreach ($ratePlans as $ratePlan) {
            $result[$ratePlan->getCode()] = $ratePlan->getName();
        }

        return $result;
    }

    /**
     * @return Array<string, array<string, mixed>> list of code => [code, name, accommodationCategory, contactInfo]
     */
    public function getAccommodationTypes(): array
    {
        $result = [];

        /** @var AccommodationType[] $accommodationTypes */
        $accommodationTypes = $this->accommodationTypeRepository->findAll();
        foreach ($accommodationTypes as $accommodationType) {
            $result[$accommodationType->getShortCode()] = [
                'code' => $accommodationType->getShortCode(),
                'name' => $accommodationType->getName(),
                'accommodationCategory' => $accommodationType->getAccommodationCategory(),
                'contactInfo' => $accommodationType->getMetadata()['contactInfo'],
            ];
        }

        return $result;
    }
}
