<?php
if (!defined('ABSPATH')) exit;

class Botami_Chatbot_Settings_Sanitizer {
    
    private $char_limits = [
        'free' => 10000,
        'pro' => 20000,
        'premium' => 40000,
        'entreprise' => 100000,
    ];

    /**
     * Main sanitization method
     * 
     * @param mixed $input
     * @param string $option_name
     * @param string $access_level
     * @return mixed
     */
    public function sanitize_option($input, $option_name = '', $access_level = 'free') {
        // If input is array, sanitize each element
        if (is_array($input)) {
            return array_map(function($value) use ($option_name, $access_level) {
                return $this->sanitize_option($value, $option_name, $access_level);
            }, $input);
        }

        $char_limit = isset($this->char_limits[$access_level]) ? $this->char_limits[$access_level] : $this->char_limits['free'];

        switch ($option_name) {
            // API Key - alphanumeric and specific characters
            case 'botami_api_key':
                $sanitized = preg_replace('/[^a-zA-Z0-9\-_.]/', '', $input);
                return substr($sanitized, 0, 255);

            // Plan - only allowed values
            case 'botami_plan':
                $allowed_plans = ['free', 'pro', 'premium', 'entreprise'];
                return in_array($input, $allowed_plans) ? $input : 'free';

            // Boolean options
            case 'botami_welcome_message_enabled':
            case 'botami_is_active':
            case 'botami_should_reload':
            case 'botami_lead_gen_enabled':
            case 'botami_lead_consent_is_active':
            case 'botami_exceed_limit':
            case 'botami_lead_email_enabled':
            case 'botami_show_powered_by':
                return $this->sanitize_boolean($input);

            // Color options - hex color validation
            case 'botami_primary_color':
            case 'botami_secondary_color':
                return $this->sanitize_color($input);

            // URL options
            case 'botami_bot_image_url':
                return esc_url_raw($input);

            case 'botami_knowledge_urls':
                return $this->sanitize_urls($input);

            case 'botami_excluded_urls':
                return $this->sanitize_excluded_urls($input);

            // Translation JSON fields
            case 'botami_placeholder_text_translations':
            case 'botami_default_message_translations':
            case 'botami_reload_text_translations':
            case 'botami_welcome_message_translations':
            case 'botami_enabled_languages':
                return $this->sanitize_json($input);

            // Input language selection
            case 'botami_input_language':
                $sanitized = sanitize_text_field($input);
                // Only allow 'en' or 'fr'
                return in_array($sanitized, ['en', 'fr']) ? $sanitized : 'en';
                
            // Integer options
            case 'botami_bot_image_id':
            case 'botami_cache_buster':
                return absint($input);

            // Long text with character limits
            case 'botami_knowledge_document':
                $sanitized = sanitize_textarea_field($input);
                return mb_substr($sanitized, 0, $char_limit, 'UTF-8');

            // JSON options
            case 'botami_quick_replies':
                return $this->sanitize_json($input);

            case 'botami_knowledge_file':
                return $this->sanitize_file_info($input);

            // Email field
            case 'botami_lead_gen_email_placeholder':
                $sanitized = sanitize_text_field($input);
                return substr($sanitized, 0, 100);

            // Regular text fields with length limits
            case 'botami_welcome_message':
            case 'botami_heading_text':
            case 'botami_online_status_text':
            case 'botami_reload_text':
            case 'botami_placeholder_text':
            case 'botami_default_message':
            case 'botami_lead_gen_intro_message':
            case 'botami_lead_gen_name_placeholder':
            case 'botami_lead_gen_field_placeholder':
            case 'botami_lead_gen_button_text':
            case 'botami_lead_gen_quick_reply':
            case 'botami_lead_gen_thank_you':
                $sanitized = sanitize_text_field($input);
                return substr($sanitized, 0, 500);

            // Longer text fields
            case 'botami_lead_gen_consentment':
                $sanitized = sanitize_textarea_field($input);
                return substr($sanitized, 0, 1000);

            // Default sanitization
            default:
                if (is_string($input)) {
                    return sanitize_text_field($input);
                }
                return $input;
        }
    }

    /**
     * Sanitize boolean values
     * 
     * @param mixed $input
     * @return string
     */
    private function sanitize_boolean($input) {
        if ($input === true || $input === 'true' || $input === '1' || $input === 1) {
            return '1';
        }
        return '0';
    }

    /**
     * Sanitize color hex values
     * 
     * @param string $input
     * @return string
     */
    private function sanitize_color($input) {
        $color = trim($input);
        
        // Add # if missing
        if (!empty($color) && $color[0] !== '#') {
            $color = '#' . $color;
        }
        
        // Validate hex color format
        if (preg_match('/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/', $color)) {
            return strtolower($color);
        }
        
        return '#007cba';
    }

    /**
     * Sanitize multiple URLs separated by ||
     * 
     * @param string $input
     * @return string
     */
    private function sanitize_urls($input) {
        if (empty($input)) {
            return '';
        }

        $urls = explode('||', $input);
        $sanitized_urls = [];

        foreach ($urls as $url) {
            $url = trim($url);
            if (!empty($url)) {
                $sanitized_url = esc_url_raw($url);
                if (filter_var($sanitized_url, FILTER_VALIDATE_URL)) {
                    $sanitized_urls[] = $sanitized_url;
                }
            }
        }

        return implode('||', $sanitized_urls);
    }

    /**
     * Sanitize excluded URLs (newline separated)
     * 
     * @param string $input
     * @return string
     */
    private function sanitize_excluded_urls($input) {
        if (empty($input)) {
            return '';
        }

        $urls = explode("\n", $input);
        $sanitized_urls = [];

        foreach ($urls as $url) {
            $url = trim($url);
            if (!empty($url)) {
                // Allow relative paths and full URLs
                if (strpos($url, '/') === 0) {
                    // Relative path
                    $sanitized_urls[] = sanitize_text_field($url);
                } else {
                    // Full URL
                    $sanitized_url = esc_url_raw($url);
                    if (filter_var($sanitized_url, FILTER_VALIDATE_URL)) {
                        $sanitized_urls[] = $sanitized_url;
                    }
                }
            }
        }

        return implode("\n", $sanitized_urls);
    }

    /**
     * Enhanced sanitize_json method that preserves key case for quick replies
     * 
     * @param string $input JSON string to sanitize
     * @return string Sanitized JSON string
     */
    private function sanitize_json($input) {
        if (empty($input)) {
            return '';
        }

        $decoded = json_decode($input, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            return '';
        }

        $sanitized = $this->sanitize_array_recursive($decoded, true);
        
        return json_encode($sanitized, JSON_UNESCAPED_UNICODE);
    }

    /**
     * Recursively sanitize array data while preserving important key names
     * 
     * @param array $array Array to sanitize
     * @param bool  $preserve_special_keys Whether to preserve special key formatting
     * @return array Sanitized array
     */
    private function sanitize_array_recursive($array, $preserve_special_keys = false) {
        $sanitized = [];
        
        // Keys that should preserve their exact case (important for JavaScript compatibility)
        $preserve_case_keys = [
            'previousQuestion',
            'previousOption',
            'id',
            'text',
            'options',
            'position'
        ];
        
        foreach ($array as $key => $value) {
            // Determine how to sanitize the key
            if (in_array($key, $preserve_case_keys, true)) {
                // Preserve exact case for critical keys, but still sanitize content
                $clean_key = preg_replace('/[^a-zA-Z0-9\-_]/', '', $key);
            } elseif ($preserve_special_keys && $this->is_id_key($key)) {
                // Preserve ID-like keys (e.g., "item-1736510123")
                $clean_key = $this->sanitize_id_key($key);
            } else {
                // Use WordPress standard key sanitization
                $clean_key = sanitize_key($key);
            }

            // Sanitize the value based on its type
            if (is_array($value)) {
                $sanitized[$clean_key] = $this->sanitize_array_recursive($value, $preserve_special_keys);
            } elseif (is_string($value)) {
                if ($this->is_id_value($key, $value)) {
                    // Preserve ID values while removing dangerous characters
                    $sanitized[$clean_key] = $this->sanitize_id_key($value);
                } else {
                    // Standard WordPress text field sanitization
                    $sanitized[$clean_key] = sanitize_text_field($value);
                }
            } else {
                // Keep other types as-is (numbers, booleans, null)
                $sanitized[$clean_key] = $value;
            }
        }
        
        return $sanitized;
    }

    /**
     * Check if a key looks like an ID that should preserve formatting
     * 
     * @param string $key Key to check
     * @return bool True if key looks like an ID
     */
    private function is_id_key($key) {
        return preg_match('/^item-\d+/', $key) || 
            preg_match('/^[a-zA-Z][\w\-]*\d+$/', $key);
    }

    /**
     * Check if a value should be treated as an ID
     * 
     * @param string $key   The array key
     * @param string $value The value to check
     * @return bool True if value should be treated as an ID
     */
    private function is_id_value($key, $value) {
        // Check for ID values in specific contexts
        if (($key === 'previousQuestion' || $key === 'id') && 
            preg_match('/^item-\d+/', $value)) {
            return true;
        }
        
        return false;
    }

    /**
     * Sanitize ID-like strings while preserving essential format
     * 
     * @param string $input ID string to sanitize
     * @return string Sanitized ID string
     */
    private function sanitize_id_key($input) {
        // Allow alphanumeric, hyphens, and underscores only
        return preg_replace('/[^a-zA-Z0-9\-_]/', '', $input);
    }

    /**
     * Sanitize file information JSON
     * 
     * @param string $input
     * @return string
     */
    private function sanitize_file_info($input) {
        if (empty($input)) {
            return '';
        }

        $file_info = json_decode($input, true);
        if (json_last_error() !== JSON_ERROR_NONE) {
            return '';
        }

        $sanitized = [];
        if (isset($file_info['filename'])) {
            $sanitized['filename'] = sanitize_file_name($file_info['filename']);
        }
        if (isset($file_info['type'])) {
            $sanitized['type'] = sanitize_mime_type($file_info['type']);
        }
        if (isset($file_info['size'])) {
            $sanitized['size'] = absint($file_info['size']);
        }
        if (isset($file_info['uploaded_at'])) {
            $sanitized['uploaded_at'] = sanitize_text_field($file_info['uploaded_at']);
        }

        return json_encode($sanitized);
    }
}