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

declare(strict_types=1);

namespace BookiFlex\Extensions\Cart\Api\Request;

use BookiFlex\Core\Api\Request\AbstractRequest;

defined( 'ABSPATH' ) || exit;

class AddToCartRequest extends AbstractRequest
{
    public function __construct(
        private readonly string $checkInDate,
        private readonly string $checkOutDate,
        private readonly int $accommodationTypeId,
        private readonly int $ratePlanId,
        private readonly int $adults,
        private readonly array $children,
        private readonly int $quantity,
        private readonly ?string $promoCode = null
    ) {
    }

    public static function fromWpRestRequest(\WP_REST_Request $request): self
    {
        $params = $request->get_json_params();

        return new self(
            checkInDate: $params['checkInDate'],
            checkOutDate: $params['checkOutDate'],
            accommodationTypeId: (int) $params['accommodationTypeId'],
            ratePlanId: (int) $params['ratePlanId'],
            adults: (int) $params['adults'],
            children: $params['children'] ?? [],
            quantity: (int) ($params['quantity'] ?? 1),
            promoCode: self::sanitizePromoCode($params['promoCode'] ?? null)
        );
    }

    /**
     * Filter a promo code down to the allowed shape: up to 20 characters,
     * letters/digits/hyphen only. Returns null when nothing valid remains,
     * so an invalid code is simply dropped rather than blocking checkout.
     */
    private static function sanitizePromoCode(mixed $code): ?string
    {
        if (!is_string($code)) {
            return null;
        }

        $filtered = substr(preg_replace('/[^A-Za-z0-9-]/', '', $code), 0, 20);

        return $filtered !== '' ? $filtered : null;
    }

    public static function getValidationRules(): array
    {
        return [
            'checkInDate' => self::dateRangeRule('checkInDate', 'checkOutDate'),
            'checkOutDate' => self::dateRule(),
            'accommodationTypeId' => self::positiveIntRule(),
            'ratePlanId' => self::positiveIntRule(),
            'adults' => [
                'required' => true,
                'validate_callback' => fn($value) => is_numeric($value) && $value >= 1 && $value <= 20,
                'sanitize_callback' => 'absint',
            ],
            'children' => [
                'required' => false,
                'type' => 'array',
                'default' => [],
                'items' => [
                    'type' => 'integer',
                    'minimum' => 0,
                    'maximum' => 21,
                ],
                'sanitize_callback' => fn($value) => array_map('intval', $value ?? []),
                'validate_callback' => 'rest_validate_request_arg',
            ],
            'quantity' => [
                'required' => false,
                'default' => 1,
                'validate_callback' => fn($value) => is_numeric($value) && $value >= 1,
                'sanitize_callback' => 'absint',
            ],
            'promoCode' => [
                'required' => false,
                'type' => 'string',
                'sanitize_callback' => 'sanitize_text_field',
            ],
        ];
    }

    public function toArray(): array
    {
        return [
            'type' => 'accommodation',
            'checkInDate' => $this->checkInDate,
            'checkOutDate' => $this->checkOutDate,
            'accommodationTypeId' => $this->accommodationTypeId,
            'ratePlanId' => $this->ratePlanId,
            'adults' => $this->adults,
            'children' => $this->children,
            'quantity' => $this->quantity,
        ];
    }

    // Getters
    public function getCheckInDate(): string { return $this->checkInDate; }
    public function getCheckOutDate(): string { return $this->checkOutDate; }
    public function getAccommodationTypeId(): int { return $this->accommodationTypeId; }
    public function getRatePlanId(): int { return $this->ratePlanId; }
    public function getAdults(): int { return $this->adults; }
    public function getChildren(): array { return $this->children; }
    public function getQuantity(): int { return $this->quantity; }
    public function getPromoCode(): ?string { return $this->promoCode; }
}
