<?php

/**
 * Settings sanitization and validation.
 *
 * Shared sanitizer logic only handles the base keys. Additional keys are
 * sanitized separately when those features are available.
 *
 * @package B3WVS\VariationSwatches\Admin\Settings
 */
namespace B3WVS\VariationSwatches\Admin\Settings;

defined( 'ABSPATH' ) || exit;
/**
 * Class Sanitizer
 *
 * Handles sanitization and validation of plugin settings.
 */
class Sanitizer {
    /**
     * Sanitize all settings from request parameters.
     *
     * @param array $params The request parameters.
     * @return array The sanitized settings.
     */
    public function sanitize( $params ) {
        if ( !is_array( $params ) ) {
            $params = array();
        }
        $settings = Defaults::get();
        $settings = $this->sanitize_shape_layout( $params, $settings );
        $settings = $this->sanitize_padding( $params, $settings );
        $settings = $this->sanitize_colors( $params, $settings );
        $settings = $this->sanitize_typography( $params, $settings );
        $settings = $this->sanitize_swatch_size( $params, $settings );
        $settings = $this->sanitize_toggles( $params, $settings );
        return $this->remove_legacy_keys( $settings );
    }

    /**
     * Remove obsolete legacy settings keys from the saved payload.
     *
     * @param array $settings Current settings being built.
     * @return array
     */
    private function remove_legacy_keys( $settings ) {
        unset($settings['swatch_size']);
        unset($settings['swatchGap']);
        unset($settings['layout_padding']);
        unset($settings['paddingTop']);
        unset($settings['paddingRight']);
        unset($settings['paddingBottom']);
        unset($settings['paddingLeft']);
        return $settings;
    }

    /**
     * Sanitize shared layout settings.
     *
     * @param array $params Request parameters.
     * @param array $settings Current settings being built.
     * @return array
     */
    private function sanitize_shape_layout( $params, $settings ) {
        $shape = ( isset( $params['shape'] ) ? sanitize_text_field( $params['shape'] ) : 'square' );
        $layout = ( isset( $params['layout'] ) ? sanitize_text_field( $params['layout'] ) : 'wrap' );
        $swatch_style = ( isset( $params['swatch_style'] ) ? sanitize_text_field( $params['swatch_style'] ) : 'underline' );
        $settings['shape'] = ( 'square' === $shape ? 'square' : 'square' );
        $settings['layout'] = ( 'wrap' === $layout ? 'wrap' : 'wrap' );
        $settings['swatch_style'] = ( 'underline' === $swatch_style ? 'underline' : 'underline' );
        $settings['swatch_gap'] = $this->sanitize_range(
            $params,
            'swatch_gap',
            8,
            0,
            40
        );
        return $settings;
    }

    /**
     * Sanitize shared padding settings.
     *
     * @param array $params Request parameters.
     * @param array $settings Current settings being built.
     * @return array
     */
    private function sanitize_padding( $params, $settings ) {
        foreach ( array(
            'top',
            'right',
            'bottom',
            'left'
        ) as $side ) {
            $padding_default = ( 'left' === $side || 'right' === $side ? 16 : 8 );
            $settings['padding_' . $side] = $this->sanitize_range(
                $params,
                'padding_' . $side,
                $padding_default,
                0,
                48
            );
            $settings['layout_padding_' . $side] = $this->sanitize_range(
                $params,
                'layout_padding_' . $side,
                5,
                0,
                48
            );
            $settings['external_padding_' . $side] = $this->sanitize_range(
                $params,
                'external_padding_' . $side,
                5,
                0,
                48
            );
        }
        return $settings;
    }

    /**
     * Sanitize shared colors.
     *
     * @param array $params Request parameters.
     * @param array $settings Current settings being built.
     * @return array
     */
    private function sanitize_colors( $params, $settings ) {
        $color_fields = array(
            'selected_color'     => '#46a5e5',
            'heading_font_color' => '#000000',
        );
        foreach ( $color_fields as $field => $default ) {
            $value = ( isset( $params[$field] ) ? sanitize_text_field( $params[$field] ) : $default );
            $settings[$field] = ( preg_match( '/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/', $value ) ? $value : $default );
        }
        $label_text_color = ( isset( $params['label_text_color'] ) ? sanitize_text_field( $params['label_text_color'] ) : '' );
        if ( '' === trim( $label_text_color ) ) {
            $settings['label_text_color'] = '';
        } else {
            $settings['label_text_color'] = ( preg_match( '/^#([0-9a-fA-F]{3}|[0-9a-fA-F]{6}|[0-9a-fA-F]{8})$/', $label_text_color ) ? $label_text_color : '' );
        }
        return $settings;
    }

    /**
     * Sanitize shared typography.
     *
     * @param array $params Request parameters.
     * @param array $settings Current settings being built.
     * @return array
     */
    private function sanitize_typography( $params, $settings ) {
        $settings['heading_font_size'] = $this->sanitize_range(
            $params,
            'heading_font_size',
            16,
            10,
            32
        );
        $settings['label_font_size'] = $this->sanitize_range(
            $params,
            'label_font_size',
            14,
            10,
            24
        );
        return $settings;
    }

    /**
     * Sanitize shared swatch sizes.
     *
     * @param array $params Request parameters.
     * @param array $settings Current settings being built.
     * @return array
     */
    private function sanitize_swatch_size( $params, $settings ) {
        $settings['swatch_width'] = $this->sanitize_range(
            $params,
            'swatch_width',
            32,
            24,
            60
        );
        $settings['swatch_height'] = $this->sanitize_range(
            $params,
            'swatch_height',
            32,
            24,
            60
        );
        return $settings;
    }

    /**
     * Sanitize shared boolean toggles.
     *
     * @param array $params Request parameters.
     * @param array $settings Current settings being built.
     * @return array
     */
    private function sanitize_toggles( $params, $settings ) {
        $defaults = Defaults::get();
        $bool_keys = array(
            'show_labels',
            'show_labels_colors',
            'enable_tooltips',
            'auto_convert_dropdowns',
            'remove_on_uninstall'
        );
        foreach ( $bool_keys as $key ) {
            $default = ( isset( $defaults[$key] ) ? (bool) $defaults[$key] : false );
            $settings[$key] = ( !isset( $params[$key] ) ? $default : !empty( $params[$key] ) );
        }
        return $settings;
    }

    /**
     * Sanitize a numeric value within a range.
     *
     * @param array  $params Request parameters.
     * @param string $key Setting key.
     * @param int    $default_value Default value.
     * @param int    $min Minimum allowed.
     * @param int    $max Maximum allowed.
     * @return int
     */
    private function sanitize_range(
        $params,
        $key,
        $default_value,
        $min,
        $max
    ) {
        $value = ( isset( $params[$key] ) ? absint( $params[$key] ) : $default_value );
        return ( $value >= $min && $value <= $max ? $value : $default_value );
    }

}
