<?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\AccommodationType;

use BookiFlex\Core\Contract\AllocationServiceInterface;
use BookiFlex\Core\Model\AccommodationType\Accommodation\AccommodationType;
use BookiFlex\Core\Model\AccommodationType\Guest\AdultGuest;
use BookiFlex\Core\Model\AccommodationType\Guest\ChildGuest;
use BookiFlex\Core\Model\AccommodationType\Scenario\PlacementScenario;
use BookiFlex\Core\Model\AccommodationType\Scenario\PlacementScenarioCollection;
use BookiFlex\Core\ValueObject\GuestConfiguration;
use BookiFlex\Core\ValueObject\PlacementLocation;

defined( 'ABSPATH' ) || exit;

/**
 * Generator of possible placement scenarios
 */
final class ScenarioGeneratorService
{
    public function __construct(
        private readonly ?AllocationServiceInterface $allocationService = null
    ) {
    }

    /**
     * Generates all possible placement scenarios for room type
     */
    public function generateScenarios(AccommodationType $accommodation): PlacementScenarioCollection
    {
        $collection = new PlacementScenarioCollection();
        $capacity = $accommodation->getCapacity();
        $rules = $accommodation->getRules();

        // Generate scenarios for adults only
        $this->generateAdultScenarios(
            $collection,
            $rules,
            $capacity->getMainPlaces(),
            $capacity->getExtraPlaces()
        );

        // Add generalized scenario with children
        if ($this->canAccommodateChildren($rules)) {
            $collection->add(new PlacementScenario(
                'children',
                $capacity->getMainPlaces(),
                $capacity->getExtraPlaces(),
                ['note' => 'Various configurations with children possible']
            ));
        }

        return $collection;
    }

    /**
     * Generates detailed scenarios with specific children configurations
     * (optional method for more detailed generation)
     */
    public function generateDetailedScenarios(
        AccommodationType $accommodation,
        array $childAgeGroups = []
    ): array {
        $basicScenarios = $this->generateScenarios($accommodation);
        $detailedScenarios = [];

        foreach ($basicScenarios as $scenario) {
            if ($scenario->isAdultsOnly()) {
                // For adults-only scenarios - just add
                $detailedScenarios[] = [
                    'scenario' => $scenario->toArray(),
                    'guests' => [
                        'adults' => $scenario->getTotalGuests(),
                        'children' => []
                    ]
                ];
            } else {
                // For scenarios with children generate several examples
                $detailedScenarios[] = [
                    'scenario' => $scenario->toArray(),
                    'guests' => [
                        'adults' => 'variable',
                        'children' => 'variable'
                    ],
                    'examples' => $this->generateChildrenExamples(
                        $accommodation,
                        $childAgeGroups
                    )
                ];
            }
        }

        return $detailedScenarios;
    }

    /**
     * Generates placement scenarios for adults only
     */
    private function generateAdultScenarios(
        PlacementScenarioCollection $collection,
        $rules,
        int $mainPlaces,
        int $extraPlaces
    ): void {
        // Scenarios on main places only
        for ($i = 1; $i <= $mainPlaces; $i++) {
            $adultGuest = new AdultGuest($i);
            if ($rules->canAccommodate($adultGuest, PlacementLocation::main())) {
                $collection->add(new PlacementScenario(
                    'adults',
                    $i,
                    0,
                    ['configuration' => "{$i} adults on main places only"]
                ));
            }
        }

        // Scenarios using extra places
        // (when main places are filled)
        if ($extraPlaces > 0) {
            $adultGuest = new AdultGuest(1);
            if ($rules->canAccommodate($adultGuest, PlacementLocation::extra())) {
                for ($j = 1; $j <= $extraPlaces; $j++) {
                    $collection->add(new PlacementScenario(
                        'adults',
                        $mainPlaces,
                        $j,
                        ['configuration' => "{$mainPlaces} on main + {$j} on extra"]
                    ));
                }
            }
        }
    }

    /**
     * Checks if children can be accommodated
     */
    private function canAccommodateChildren($rules): bool
    {
        // Check if there's at least one option for children accommodation
        foreach ($rules->getAllowedOptions() as $option) {
            if ($option->getGuestType() instanceof ChildGuest) {
                return true;
            }
        }
        return false;
    }

    /**
     * Generates placement examples with children
     */
    private function generateChildrenExamples(
        AccommodationType $accommodation,
        array $childAgeGroups
    ): array {
        $examples = [];

        // If allocation service not injected, create base instance
        $placementService = $this->allocationService ?? new BaseAllocationService();

        // Example 1: Family with one child
        if ($placementService->canAccommodate($accommodation, new GuestConfiguration(2, [5]))) {
            $examples[] = [
                'adults' => 2,
                'children' => [5],
                'description' => 'Couple with 1 child (5 years)'
            ];
        }

        // Example 2: Family with two children
        if ($placementService->canAccommodate($accommodation, new GuestConfiguration(2, [3, 7]))) {
            $examples[] = [
                'adults' => 2,
                'children' => [3, 7],
                'description' => 'Couple with 2 children (3 and 7 years)'
            ];
        }

        // Example 3: Single parent with child
        if ($placementService->canAccommodate($accommodation, new GuestConfiguration(1, [10]))) {
            $examples[] = [
                'adults' => 1,
                'children' => [10],
                'description' => 'Single parent with 1 child (10 years)'
            ];
        }

        return $examples;
    }
}
