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

defined( 'ABSPATH' ) || exit;

/**
 * Onboarding Configuration Value Object
 *
 * Encapsulates user input for onboarding wizard with mode-specific validation.
 *
 * @package BookiFlex\Extensions\Onboarding\ValueObject
 * @since   1.0.0
 */
class OnboardingConfiguration
{
    /**
     * Onboarding Configuration constructor
     *
     * @param OnboardingMode      $mode                 Onboarding mode
     * @param string|null         $currency             ISO 4217 currency code (required for quick_setup)
     * @param AccommodationType[] $accommodationTypes   List of accommodation types (required for quick_setup)
     * @param int[]               $paymentTypeIds       Selected payment type IDs (required for quick_setup)
     * @param int|null            $cancellationPolicyId Selected cancellation policy ID (required for quick_setup)
     * @param string|null         $companyName          Company legal/trading name (required for quick_setup)
     * @param string|null         $companyAddress       Company address (required for quick_setup)
     * @param string|null         $companyPhone         Company phone (optional)
     * @param string|null         $companyEmail         Company email (required for quick_setup)
     *
     * @throws \InvalidArgumentException If validation fails
     */
    public function __construct(
        public readonly OnboardingMode $mode,
        public readonly ?string $currency = null,
        public readonly array $accommodationTypes = [],
        public readonly array $paymentTypeIds = [],
        public readonly ?int $cancellationPolicyId = null,
        public readonly ?string $companyName = null,
        public readonly ?string $companyAddress = null,
        public readonly ?string $companyPhone = null,
        public readonly ?string $companyEmail = null,
    ) {
        $this->validate();
    }

    /**
     * Validate configuration based on mode
     *
     * @return void
     * @throws \InvalidArgumentException If validation fails
     */
    public function validate(): void
    {
        if ($this->mode->isQuickSetup()) {
            if (empty($this->currency) || strlen($this->currency) !== 3) {
                throw new \InvalidArgumentException('Valid ISO 4217 currency required for quick setup');
            }

            if (empty($this->accommodationTypes)) {
                throw new \InvalidArgumentException('At least one accommodation type required for quick setup');
            }

            if (empty($this->paymentTypeIds)) {
                throw new \InvalidArgumentException('At least one payment method required for quick setup');
            }

            if ($this->cancellationPolicyId === null) {
                throw new \InvalidArgumentException('Cancellation policy required for quick setup');
            }

            if (empty($this->companyName)) {
                throw new \InvalidArgumentException('Company name required for quick setup');
            }

            if (empty($this->companyAddress)) {
                throw new \InvalidArgumentException('Company address required for quick setup');
            }

            if (empty($this->companyEmail)) {
                throw new \InvalidArgumentException('Company email required for quick setup');
            }

            // Validate each accommodation
            foreach ($this->accommodationTypes as $index => $accommodation) {
                $accommodation->validate();

                // Ensure weeklyPricing is present for QuickSetup mode
                if ($accommodation->weeklyPricing === null) {
                    throw new \InvalidArgumentException(
                        sprintf('weeklyPricing required for accommodation at index %d in quick setup', $index)
                    );
                }
            }
        }
    }

    /**
     * Convert to array representation
     *
     * @return array{mode: string, currency: string|null, accommodationTypes: array, paymentTypeIds: int[], cancellationPolicyId: int|null}
     */
    public function toArray(): array
    {
        return [
            'mode' => $this->mode->value,
            'currency' => $this->currency,
            'accommodationTypes' => array_map(fn($a) => $a->toArray(), $this->accommodationTypes),
            'paymentTypeIds' => $this->paymentTypeIds,
            'cancellationPolicyId' => $this->cancellationPolicyId,
            'companyName' => $this->companyName,
            'companyAddress' => $this->companyAddress,
            'companyPhone' => $this->companyPhone,
            'companyEmail' => $this->companyEmail,
        ];
    }

    /**
     * Create from array
     *
     * @param  array<string, mixed> $data Array representation
     * @return self
     * @throws \InvalidArgumentException If validation fails
     */
    public static function fromArray(array $data): self
    {
        $mode = OnboardingMode::from($data['mode'] ?? throw new \InvalidArgumentException('mode required'));

        $accommodationTypes = [];
        if (isset($data['accommodationTypes']) && is_array($data['accommodationTypes'])) {
            foreach ($data['accommodationTypes'] as $accData) {
                $accommodationTypes[] = AccommodationType::fromArray($accData);
            }
        }

        return new self(
            mode: $mode,
            currency: $data['currency'] ?? null,
            accommodationTypes: $accommodationTypes,
            paymentTypeIds: $data['paymentTypeIds'] ?? [],
            cancellationPolicyId: $data['cancellationPolicyId'] ?? null,
            companyName: $data['companyName'] ?? null,
            companyAddress: $data['companyAddress'] ?? null,
            companyPhone: $data['companyPhone'] ?? null,
            companyEmail: $data['companyEmail'] ?? null,
        );
    }
}
