<?php

namespace FuseCommerce\Helpers;

use FuseCommerce\Services\FileStorageService;
use FuseCommerce\Utils\OptionUtils;

/**
 * Helper class for managing filter component configuration
 * Handles ordering and visibility settings for frontend filters
 */
class FilterConfigHelper {

    private const OPTION_KEY = 'filter_components';

    /**
     * Get filter configuration from options or generate default
     *
     * @return array Array of filter components with order and visibility
     */
    public static function getFilterConfiguration(): array {
        $optionUtils = OptionUtils::getInstance();
        $savedConfig = $optionUtils->getOption(self::OPTION_KEY, null);

        // If no saved configuration, generate default from index data
        if ($savedConfig === null || empty($savedConfig)) {
            return self::getDefaultConfiguration();
        }

        // Handle case where config might be saved as JSON string
        if (is_string($savedConfig)) {
            $decoded = json_decode($savedConfig, true);
            if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
                return $decoded;
            }
            // If decode fails, generate default
            return self::getDefaultConfiguration();
        }

        return is_array($savedConfig) ? $savedConfig : self::getDefaultConfiguration();
    }

    /**
     * Generate default filter configuration from indexed data
     * Shows all components in default order: Categories, Attributes, Price Range
     *
     * @return array Default configuration array
     */
    public static function getDefaultConfiguration(): array {
        $config = [];
        $order = 0;

        // Add Search (first by default)
        $config[] = [
            'id' => 'search',
            'type' => 'search',
            'label' => 'Search Products',
            'visible' => true,
            'order' => $order++
        ];

        // Add Categories
        $config[] = [
            'id' => 'categories',
            'type' => 'category',
            'label' => 'Categories',
            'visible' => true,
            'order' => $order++
        ];

        // Add Tags
        $config[] = [
            'id' => 'tags',
            'type' => 'tag',
            'label' => 'Tags',
            'visible' => true,
            'order' => $order++
        ];

        // Add Attributes (dynamic from attributes.json)
        $attributes = self::getAvailableAttributes();
        foreach ($attributes as $attribute) {
            $config[] = [
                'id' => $attribute['name'],
                'type' => 'attribute',
                'label' => $attribute['label'],
                'visible' => true,
                'order' => $order++
            ];
        }

        // Add Price Range (always last by default)
        $config[] = [
            'id' => 'price_range',
            'type' => 'price',
            'label' => 'Price Range',
            'visible' => true,
            'order' => $order++
        ];

        return $config;
    }

    /**
     * Merge saved configuration with fresh index data
     * Preserves user's order and visibility settings while adding new attributes
     *
     * @return array Merged configuration
     */
    public static function mergeWithIndexData(): array {
        $savedConfig = OptionUtils::getInstance()->getOption(self::OPTION_KEY, []);

        // Handle case where config might be saved as JSON string
        if (is_string($savedConfig)) {
            $decoded = json_decode($savedConfig, true);
            if (json_last_error() === JSON_ERROR_NONE && is_array($decoded)) {
                $savedConfig = $decoded;
            } else {
                $savedConfig = [];
            }
        }

        $availableAttributes = self::getAvailableAttributes();

        // If no saved config, just return default
        if (empty($savedConfig) || !is_array($savedConfig)) {
            return self::getDefaultConfiguration();
        }

        // Create maps for easier lookup
        $savedMap = [];
        foreach ($savedConfig as $item) {
            if (is_array($item) && isset($item['id'])) {
                $savedMap[$item['id']] = $item;
            }
        }

        $attributeMap = [];
        foreach ($availableAttributes as $attr) {
            $attributeMap[$attr['name']] = $attr;
        }

        // Start with saved config, update labels for existing attributes
        $mergedConfig = [];
        foreach ($savedConfig as $item) {
            if ($item['type'] === 'attribute') {
                // Check if attribute still exists in index
                if (isset($attributeMap[$item['id']])) {
                    // Update label in case it changed
                    $item['label'] = $attributeMap[$item['id']]['label'];
                    $mergedConfig[] = $item;
                }
                // If attribute no longer exists, skip it (removed from WooCommerce)
            } else {
                // Keep categories, tags, price_range, and search as-is
                $mergedConfig[] = $item;
            }
        }

        // Add new attributes that weren't in saved config
        $maxOrder = !empty($mergedConfig) ? max(array_column($mergedConfig, 'order')) : -1;
        foreach ($availableAttributes as $attribute) {
            if (!isset($savedMap[$attribute['name']])) {
                // New attribute, add at the end
                $mergedConfig[] = [
                    'id' => $attribute['name'],
                    'type' => 'attribute',
                    'label' => $attribute['label'],
                    'visible' => true,
                    'order' => ++$maxOrder
                ];
            }
        }

        // Re-sort by order
        usort($mergedConfig, function($a, $b) {
            return $a['order'] <=> $b['order'];
        });

        return $mergedConfig;
    }

    /**
     * Save filter configuration to options
     *
     * @param array $config Configuration array to save
     * @return bool Success status
     */
    public static function saveFilterConfiguration(array $config): bool {
        if (!self::validateConfiguration($config)) {
            return false;
        }

        $optionUtils = OptionUtils::getInstance();
        return $optionUtils->setOption(self::OPTION_KEY, $config);
    }

    /**
     * Validate filter configuration structure
     *
     * @param array $config Configuration to validate
     * @return bool True if valid
     */
    public static function validateConfiguration(array $config): bool {
        if (!is_array($config)) {
            return false;
        }

        foreach ($config as $item) {
            // Check required keys
            if (!isset($item['id']) || !isset($item['type']) || !isset($item['label']) ||
                !isset($item['visible']) || !isset($item['order'])) {
                return false;
            }

            // Validate type
            if (!in_array($item['type'], ['category', 'tag', 'attribute', 'price', 'search'])) {
                return false;
            }

            // Validate visible is boolean
            if (!is_bool($item['visible'])) {
                return false;
            }

            // Validate order is numeric
            if (!is_numeric($item['order'])) {
                return false;
            }
        }

        return true;
    }

    /**
     * Get available attributes from attributes.json
     *
     * @return array Array of attributes with name and label
     */
    private static function getAvailableAttributes(): array {
        $fileStorage = new FileStorageService();
        $attributesJson = $fileStorage->read('attributes.json');

        if ($attributesJson === null) {
            return [];
        }

        $attributes = json_decode($attributesJson, true);
        if (!is_array($attributes)) {
            return [];
        }

        return $attributes;
    }

    /**
     * Check if indexing data exists (categories.json and attributes.json)
     *
     * @return bool True if both files exist
     */
    public static function hasIndexingData(): bool {
        $fileStorage = new FileStorageService();
        return $fileStorage->jsonFileExists('categories.json') &&
               $fileStorage->jsonFileExists('attributes.json') &&
               $fileStorage->jsonFileExists('tags.json');
    }

    /**
     * Get visible filters in order for frontend rendering
     *
     * @return array Array of visible filter components sorted by order
     */
    public static function getVisibleFilters(): array {
        $config = self::getFilterConfiguration();

        // Filter only visible items
        // Handle both boolean true and string "true" or "1" (after sanitization)
        $visibleFilters = array_filter($config, function($item) {
            if (!isset($item['visible'])) {
                return false;
            }

            // Handle different possible values after sanitization
            $visible = $item['visible'];
            if (is_bool($visible)) {
                return $visible === true;
            }
            if (is_string($visible)) {
                return in_array(strtolower($visible), ['true', '1', 'yes']);
            }
            if (is_numeric($visible)) {
                return (int)$visible === 1;
            }

            return false;
        });

        // Sort by order
        usort($visibleFilters, function($a, $b) {
            return $a['order'] <=> $b['order'];
        });

        return $visibleFilters;
    }
}
