<?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\Model\Reservation;

use BookiFlex\Core\Exception\MoneyCalculationException;
use Brick\Money\Money;
use DateTimeImmutable;

defined( 'ABSPATH' ) || exit;

/**
 * Represents an accommodation item in a reservation (room, bed, apartment, etc.).
 *
 * Each item represents a single night's accommodation with specific:
 * - Accommodation type (room category, bed type)
 * - Rate plan (pricing rules and conditions)
 * - Guest configuration (adults and children)
 * - Date of stay
 *
 * @package BookiFlex\Core\Model\Reservation
 */
class ReservationAccommodationItem extends AbstractReservationItem
{
    /**
     * Create a new accommodation item.
     *
     * @param string $name Accommodation name/description
     * @param Money $price Price for this night
     * @param DateTimeImmutable $date Date of stay
     * @param string $accommodationTypeCode Accommodation type identifier (e.g., 'DBL', 'SUITE')
     * @param string $ratePlanCode Rate plan identifier (e.g., 'BB', 'HB', 'FLEX')
     * @param int $adults Number of adult guests
     * @param array $children Array of children ages
     * @param array $details Additional pricing details (breakdown, inclusions, etc.)
     * @param string $unit Room/unit number (e.g., '101', 'A-12')
     *
     * @throws MoneyCalculationException If price calculation fails
     */
    public function __construct(
        string $name,
        Money $price,
        private readonly DateTimeImmutable $date,
        private readonly string $accommodationTypeCode,
        private readonly string $ratePlanCode,
        private readonly int $adults,
        private readonly array $children,
        array $details,
        private string $unit = '',
    ) {
        parent::__construct($name, $price);
        $this->details = $details;
    }

    // ========================================================================
    // Specific Properties Access
    // ========================================================================

    /**
     * Get date of stay for this accommodation.
     *
     * @return DateTimeImmutable
     */
    public function getDate(): DateTimeImmutable
    {
        return $this->date;
    }

    /**
     * Get accommodation type code.
     * Identifies the room category or bed type.
     *
     * @return string Code like 'DBL', 'TWIN', 'SUITE', etc.
     */
    public function getAccommodationTypeCode(): string
    {
        return $this->accommodationTypeCode;
    }

    /**
     * Get rate plan code.
     * Identifies pricing rules and included services.
     *
     * @return string Code like 'BB' (Bed & Breakfast), 'RO' (Room Only), etc.
     */
    public function getRatePlanCode(): string
    {
        return $this->ratePlanCode;
    }

    /**
     * Get number of adult guests.
     *
     * @return int Number of adults (typically 18+ years)
     */
    public function getAdults(): int
    {
        return $this->adults;
    }

    /**
     * Get children information.
     *
     * @return array Array of children ages or child objects
     */
    public function getChildren(): array
    {
        return $this->children;
    }

    /**
     * Get total number of guests.
     *
     * @return int Sum of adults and children
     */
    public function getTotalGuests(): int
    {
        return $this->adults + count($this->children);
    }

    /**
     * Get room/unit number.
     *
     * @return string Room number or empty if not assigned
     */
    public function getUnit(): string
    {
        return $this->unit;
    }

    /**
     * Set or update room/unit number.
     * Used when assigning specific rooms to reservations.
     *
     * @param string $value Room/unit number
     */
    public function setUnit(string $value): void
    {
        $this->unit = $value;
    }

    /**
     * Check if room is assigned.
     *
     * @return bool True if unit number is set
     */
    public function hasUnitAssigned(): bool
    {
        return !empty($this->unit);
    }

    // ========================================================================
    // Helper Methods
    // ========================================================================

    /**
     * Check if this accommodation is for a specific date.
     *
     * @param DateTimeImmutable $date Date to check
     * @return bool True if dates match
     */
    public function isForDate(DateTimeImmutable $date): bool
    {
        return $this->date->format('Y-m-d') === $date->format('Y-m-d');
    }

    /**
     * Get formatted guest configuration string.
     *
     * @return string E.g., "2 Adults, 1 Child"
     */
    public function getGuestConfigurationString(): string
    {
        $parts = [];

        if ($this->adults > 0) {
            $parts[] = $this->adults . ' ' . ($this->adults === 1 ? 'Adult' : 'Adults');
        }

        $childrenCount = count($this->children);
        if ($childrenCount > 0) {
            $parts[] = $childrenCount . ' ' . ($childrenCount === 1 ? 'Child' : 'Children');
        }

        return implode(', ', $parts) ?: 'No guests';
    }
}
