<?php

/**
 * Provides data sanitization logic.
 *
 * @package WooCommerce\PayPalCommerce\Settings\Service
 */
declare (strict_types=1);
namespace WooCommerce\PayPalCommerce\Settings\Service;

use WooCommerce\PayPalCommerce\Settings\DTO\LocationStylingDTO;
use WooCommerce\PayPalCommerce\Settings\DTO\PayLaterMessagingDTO;
/**
 * DataSanitizer service. Generally used by REST endpoints (sanitize input data)
 * and data models (sanitize data during DB access)
 */
class DataSanitizer
{
    /**
     * Sanitizes the provided styling data.
     *
     * @param mixed   $data     The styling data to sanitize.
     * @param ?string $location Name of the location.
     * @return LocationStylingDTO Styling data.
     */
    public function sanitize_location_style($data, ?string $location = null): LocationStylingDTO
    {
        if ($data instanceof LocationStylingDTO) {
            if ($location) {
                $data->location = $location;
            }
            return $data;
        }
        if (is_object($data)) {
            $data = (array) $data;
        }
        if (!is_array($data)) {
            return new LocationStylingDTO($location ?? '');
        }
        if (null === $location) {
            $location = $data['location'] ?? '';
        }
        $is_enabled = $this->sanitize_bool($data['enabled'] ?? \true);
        $shape = $this->sanitize_text($data['shape'] ?? 'rect');
        $label = $this->sanitize_text($data['label'] ?? 'pay');
        $color = $this->sanitize_text($data['color'] ?? 'gold');
        $layout = $this->sanitize_text($data['layout'] ?? 'vertical');
        $tagline = $this->sanitize_bool($data['tagline'] ?? \false);
        $methods = $this->sanitize_array($data['methods'] ?? array(), array($this, 'sanitize_text'));
        return new LocationStylingDTO($location, $is_enabled, $methods, $shape, $label, $color, $layout, $tagline);
    }
    /**
     * Sanitizes the provided Pay Later messaging data.
     *
     * @param mixed   $data     The messaging data to sanitize.
     * @param ?string $location Name of the location.
     * @return PayLaterMessagingDTO Messaging data.
     */
    public function sanitize_paylater_messaging($data, ?string $location = null): PayLaterMessagingDTO
    {
        if ($data instanceof PayLaterMessagingDTO) {
            if ($location) {
                $data->location = $location;
            }
            return $data;
        }
        if (is_object($data)) {
            $data = (array) $data;
        }
        if (!is_array($data)) {
            return new PayLaterMessagingDTO($location ?? '');
        }
        if (null === $location) {
            $location = $data['location'] ?? '';
        }
        return new PayLaterMessagingDTO($location, $this->sanitize_bool($data['enabled'] ?? \false), $this->sanitize_text($data['layout'] ?? 'text'), $this->sanitize_text($data['logo_type'] ?? $data['logo-type'] ?? 'inline'), $this->sanitize_text($data['logo_position'] ?? $data['logo-position'] ?? 'left'), $this->sanitize_text($data['text_color'] ?? $data['text-color'] ?? 'black'), $this->sanitize_text($data['text_size'] ?? $data['text-size'] ?? '12'), $this->sanitize_text($data['flex_color'] ?? $data['color'] ?? 'black'), $this->sanitize_text($data['flex_ratio'] ?? $data['ratio'] ?? '8x1'));
    }
    /**
     * Helper. Ensures the value is a string.
     *
     * @param mixed  $value   Value to sanitize.
     * @param string $default Default value.
     * @return string Sanitized string.
     */
    public function sanitize_text($value, string $default = ''): string
    {
        return sanitize_text_field($value ?? $default);
    }
    /**
     * Helper. Ensures the matches one of the provided enumerations.
     *
     * The comparison is case-insensitive, if no valid default is given, the
     * first $valid_values entry is returned on failure.
     *
     * @param mixed    $value        Value to sanitize.
     * @param string[] $valid_values List of allowed return values. Must use ASCII-only characters.
     * @param string   $default      Default value.
     * @return string Sanitized string.
     */
    public function sanitize_enum($value, array $valid_values, string $default = ''): string
    {
        if (empty($valid_values)) {
            return $default;
        }
        $value = $this->sanitize_text($value);
        $match = $this->find_enum_value($value, $valid_values);
        if ($match) {
            return $match;
        }
        $default_match = $this->find_enum_value($default, $valid_values);
        if ($default_match) {
            return $default_match;
        }
        return $valid_values[0];
    }
    /**
     * Helper. Ensures the value is a boolean.
     *
     * @param mixed $value Value to sanitize.
     * @return bool Sanitized boolean.
     */
    public function sanitize_bool($value): bool
    {
        return filter_var($value, \FILTER_VALIDATE_BOOLEAN);
    }
    /**
     * Helper. Ensures the value is an integer.
     *
     * Attention: When passing a non-integer value (like 12.5 or "12a") the
     * function will return 0.
     *
     * @param mixed $value Value to sanitize.
     * @return int Sanitized integer.
     */
    public function sanitize_int($value): int
    {
        return (int) filter_var($value, \FILTER_VALIDATE_INT);
    }
    /**
     * Helper. Ensures the value is an array and all items are sanitized.
     *
     * @param null|array $array             Value to sanitize.
     * @param callable   $sanitize_callback Callback to sanitize each item in the array.
     * @return array Array with sanitized items.
     */
    public function sanitize_array(?array $array, callable $sanitize_callback): array
    {
        if (!is_array($array)) {
            return array();
        }
        return array_map($sanitize_callback, $array);
    }
    /**
     * Helper function to find a case-insensitive match in the valid values array.
     *
     * @param string   $value        Value to find.
     * @param string[] $valid_values List of allowed values.
     * @return string|null Matching value if found, null otherwise.
     */
    private function find_enum_value(string $value, array $valid_values): ?string
    {
        foreach ($valid_values as $valid_value) {
            // Compare both strings case-insensitive and binary safe.
            // Note: This function is safe for ASCII but can fail for unicode-characters.
            if (0 === strcasecmp($value, $valid_value)) {
                return $valid_value;
            }
        }
        return null;
    }
}
