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

declare(strict_types=1);

namespace BookiFlex\Extensions\Onboarding\Service;

use BookiFlex\Extensions\Onboarding\Contract\OnboardingHandlerInterface;
use BookiFlex\Extensions\Onboarding\ValueObject\OnboardingConfiguration;
use BookiFlex\Extensions\Onboarding\ValueObject\OnboardingResult;
use BookiFlex\Core\Service\CptCreator\CptCreatorInterface;

defined( 'ABSPATH' ) || exit;

/**
 * Onboarding Service
 *
 * Main orchestrator for onboarding process.
 * Routes to appropriate handler based on mode and marks onboarding complete.
 *
 * @package BookiFlex\Extensions\Onboarding\Service
 * @since   1.0.0
 */
class OnboardingService
{
    /**
     * OnboardingService constructor
     *
     * @param OnboardingStateManager                    $stateManager State manager
     * @param CptCreatorInterface                       $cptCreator   CPT creator
     * @param array<string, OnboardingHandlerInterface> $handlers     Mode handlers map
     */
    public function __construct(
        private readonly OnboardingStateManager $stateManager,
        private readonly CptCreatorInterface $cptCreator,
        private readonly array $handlers
    ) {
    }

    /**
     * Execute onboarding based on configuration
     *
     * @param  OnboardingConfiguration $config Onboarding configuration
     * @return OnboardingResult Execution result
     * @throws \RuntimeException If handler not found or execution fails
     */
    public function execute(OnboardingConfiguration $config): OnboardingResult
    {
        // Get handler for mode
        $handler = $this->getHandler($config->mode->value);

        try {
            // Execute handler
            $result = $handler->handle($config, $this->cptCreator, $this->stateManager);

            // Mark onboarding complete
            $this->stateManager->markComplete(
                $config->mode,
                $this->buildMetadata($config, $result)
            );

            return $result;
        } catch (\Exception $e) {
            // Re-throw with context
            throw new \RuntimeException(
                sprintf(
                    'Onboarding execution failed for mode %1$s: %2$s',
                    $config->mode->value,
                    $e->getMessage()
                ),
                0,
                $e
            );
        }
    }

    /**
     * Get handler for mode
     *
     * @param  string $mode Mode value (quick_setup, test_data, manual)
     * @return OnboardingHandlerInterface Handler instance
     * @throws \RuntimeException If handler not found
     */
    private function getHandler(string $mode): OnboardingHandlerInterface
    {
        if (!isset($this->handlers[$mode])) {
            throw new \RuntimeException(
                sprintf(
					'No handler found for mode: %s',
					$mode
                )
            );
        }

        return $this->handlers[$mode];
    }

    /**
     * Build metadata for state storage
     *
     * @param  OnboardingConfiguration $config Configuration
     * @param  OnboardingResult        $result Result
     * @return array<string, mixed> Metadata
     */
    private function buildMetadata(OnboardingConfiguration $config, OnboardingResult $result): array
    {
        $metadata = [
            'mode' => $config->mode->value,
            'success' => $result->success,
        ];

        // Add mode-specific metadata
        if ($config->mode->isQuickSetup()) {
            $metadata['currency'] = $config->currency;
            $metadata['accommodationCount'] = count($config->accommodationTypes);
            $metadata['paymentTypeCount'] = count($config->paymentTypeIds);
        }

        return $metadata;
    }
}
