<?php

namespace AIPT\Utils\ProductFilter;

if ( ! defined( 'ABSPATH' ) ) {
	exit;
}

/**
 * ProductFilterMapper - Filtre parametrelerini dönüştürmek için kullanılan yardımcı sınıf
 *
 * Bu sınıf, frontend'den gelen filtre parametrelerini backend filter builder'ın
 * anlayabileceği formata dönüştürür ve ters dönüşüm işlemlerini gerçekleştirir.
 *
 * @version 2.4.5
 * @since 2.4.2 Cleaned up debug logs and improved code structure
 * @since 2.4.3 Added filter_logic support and adaptResponse() for format compatibility
 * @since 2.4.4 Added Polylang multilingual compatibility for category/tag term filtering
 * @since 2.4.5 Extracted Polylang logic to PolylangTermHandler (SOLID/SRP)
 */
class ProductFilterMapper {

    /**
     * Parses comma-separated multi-value string into array
     *
     * @param string $value Comma-separated value
     * @return array Array of trimmed values
     */
    private static function parseMultiValue(string $value): array {
        if (empty($value)) {
            return [];
        }
        return array_values(array_filter(array_map('trim', explode(',', $value))));
    }

    public static function fromRequest($params) {
        $filterParams = [];

        $filterParams['search'] = isset($params['search']) ? $params['search'] : '';

        if (!empty($params['category'])) {
            $cats = self::parseMultiValue(sanitize_text_field($params['category']));
            $filterParams['category'] = $cats;
        } else {
            $filterParams['category'] = [];
        }

        $filterParams['page'] = isset($params['page']) ? absint($params['page']) : 1;
        $filterParams['per_page'] = isset($params['per_page']) ? absint($params['per_page']) : 10;

        if (isset($params['orderby']) && strpos($params['orderby'], '_') !== false) {
            $parts = explode('_', $params['orderby'], 2);
            $filterParams['orderby'] = $parts[0];
            $filterParams['order'] = isset($parts[1]) ? $parts[1] : 'DESC';
        } else {
            $filterParams['orderby'] = isset($params['orderby']) ? $params['orderby'] : 'date';
            $filterParams['order'] = isset($params['order']) ? $params['order'] : 'DESC';
        }

        if (!empty($params['status'])) {
            $stock_statuses = ['instock', 'outofstock', 'onbackorder'];
            if (in_array($params['status'], $stock_statuses, true)) {
                $filterParams['stock_status'] = $params['status'];
            } else {
                $filterParams['status'] = $params['status'];
            }
        }

        if (!empty($params['stock_status'])) {
            $filterParams['stock_status'] = $params['stock_status'];
        }

        if (isset($params['hasDescription'])) {
            $filterParams['hasDescription'] = filter_var($params['hasDescription'], FILTER_VALIDATE_BOOLEAN);
        }

        if (isset($params['hasShortDescription'])) {
            $filterParams['hasShortDescription'] = filter_var($params['hasShortDescription'], FILTER_VALIDATE_BOOLEAN);
        }

        if (isset($params['descriptionFilter'])) {
            $descriptionMapping = self::mapDescriptionFilter($params['descriptionFilter']);
            if ($descriptionMapping['hasDescription'] !== null) {
                $filterParams['hasDescription'] = $descriptionMapping['hasDescription'];
            }
            if ($descriptionMapping['hasShortDescription'] !== null) {
                $filterParams['hasShortDescription'] = $descriptionMapping['hasShortDescription'];
            }
            if ($descriptionMapping['hasTags'] !== null) {
                $filterParams['hasTags'] = $descriptionMapping['hasTags'];
            }
        }

        if (isset($params['has_image']) && $params['has_image'] !== '') {
            $filterParams['has_image'] = filter_var($params['has_image'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
        }

        if (isset($params['has_gallery']) && $params['has_gallery'] !== '') {
            $filterParams['has_gallery'] = filter_var($params['has_gallery'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
        }

        if (!empty($params['sku_status'])) {
            $sku_status = sanitize_text_field($params['sku_status']);
            if ($sku_status === 'has_sku') {
                $filterParams['has_sku'] = true;
            } elseif ($sku_status === 'no_sku') {
                $filterParams['has_sku'] = false;
            }
        }

        if (!empty($params['product_type'])) {

            if (is_string($params['product_type']) && strpos($params['product_type'], ',') !== false) {
                $types = array_filter(array_map('trim', explode(',', $params['product_type'])));
                $params['product_type'] = array_map('sanitize_text_field', $types);
            }
            $filterParams['product_type'] = is_array($params['product_type'])
                ? array_map('sanitize_text_field', $params['product_type'])
                : sanitize_text_field($params['product_type']);
        }

        if (isset($params['featured']) && $params['featured'] !== '') {
            $filterParams['featured'] = filter_var($params['featured'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
        }

        if (isset($params['on_sale']) && $params['on_sale'] !== '') {
            $filterParams['on_sale'] = filter_var($params['on_sale'], FILTER_VALIDATE_BOOLEAN, FILTER_NULL_ON_FAILURE);
        }

        if (!empty($params['filter_logic'])) {
            $logic = strtolower(sanitize_text_field($params['filter_logic']));
            if (in_array($logic, ['and', 'or'], true)) {
                $filterParams['filter_logic'] = $logic;
            }
        }

        return $filterParams;
    }

    /**
     * Filtreleme parametrelerini ProductFilterBuilder'a uygular
     *
     * @param ProductFilterBuilder $builder Filter builder instance
     * @param array $params Filtre parametreleri
     * @return ProductFilterBuilder Parametreleri uygulanmış builder
     */
    public static function applyToBuilder(ProductFilterBuilder $builder, $params) {

        if (!empty($params['filter_logic'])) {
            $builder->filterLogic($params['filter_logic']);
        }

        if (!empty($params['search'])) {
            $builder->search($params['search']);
        }

        if (!empty($params['category'])) {
            $builder->category($params['category']);
        }

        $builder->pagination(
            isset($params['page']) ? $params['page'] : 1,
            isset($params['per_page']) ? $params['per_page'] : 10
        );

        $orderby = isset($params['orderby']) ? $params['orderby'] : 'date';
        $order = isset($params['order']) ? strtoupper($params['order']) : 'DESC';
        $builder->orderBy($orderby, $order);

        if (!empty($params['status'])) {
            $builder->status($params['status']);
        }

        if (!empty($params['stock_status'])) {
            $builder->stockStatus($params['stock_status']);
        }

        $hasDescription = isset($params['hasDescription']) ? $params['hasDescription'] : null;
        $hasShortDescription = isset($params['hasShortDescription']) ? $params['hasShortDescription'] : null;

        if ($hasDescription !== null || $hasShortDescription !== null) {
            $builder->descriptions($hasDescription, $hasShortDescription);
        }

        if (isset($params['hasTags'])) {
            $builder->tags($params['hasTags']);
        }

        if (isset($params['has_image'])) {
            $builder->image($params['has_image']);
        }

        if (isset($params['has_gallery'])) {
            $builder->gallery($params['has_gallery']);
        }

        if (isset($params['has_sku'])) {
            $builder->sku($params['has_sku']);
        }

        if (!empty($params['product_type'])) {
            $builder->productType($params['product_type']);
        }

        if (isset($params['featured'])) {
            $builder->featured($params['featured']);
        }

        if (isset($params['on_sale'])) {
            $builder->onSale($params['on_sale']);
        }

        return $builder;
    }

    /**
     * UI için açıklama filtresi değerini backend formatına dönüştürür
     *
     * @param string $descriptionFilter UI filtre değeri
     * @return array Açıklama filtre parametreleri
     */
    public static function mapDescriptionFilter($descriptionFilter) {
        $result = [
            'hasDescription' => null,
            'hasShortDescription' => null,
            'hasTags' => null
        ];

        switch ($descriptionFilter) {
            case 'with_both':
                $result['hasDescription'] = true;
                $result['hasShortDescription'] = true;
                break;
            case 'with_full':
                $result['hasDescription'] = true;
                $result['hasShortDescription'] = false;
                break;
            case 'with_short':
                $result['hasDescription'] = false;
                $result['hasShortDescription'] = true;
                break;
            case 'without_both':
                $result['hasDescription'] = false;
                $result['hasShortDescription'] = false;
                break;
            case 'without_full':
                $result['hasDescription'] = false;
                break;
            case 'without_short':
                $result['hasShortDescription'] = false;
                break;
            case 'with_tags':
                $result['hasTags'] = true;
                break;
            case 'without_tags':
                $result['hasTags'] = false;
                break;
        }

        return $result;
    }

    /**
     * Adapts ProductFilterBuilder response to match ProductListingService format
     *
     * This ensures backward compatibility when migrating from ProductListingService
     * to ProductFilterBuilder across different generators.
     *
     * ProductFilterBuilder returns:
     *   ['products' => [], 'total' => int, 'total_pages' => int]
     *
     * ProductListingService returns:
     *   ['success' => bool, 'products' => [], 'total' => int, 'totalPages' => int, 'page' => int, 'perPage' => int]
     *
     * @param array $result     Result from ProductFilterBuilder::getProducts()
     * @param array $params     Original filter params (to extract page/per_page)
     * @param bool  $includeFilters Whether to include the filters in response
     * @return array Adapted response matching ProductListingService format
     */
    public static function adaptResponse(array $result, array $params = [], bool $includeFilters = false): array {
        $adapted = [
            'success'    => !isset($result['error']),
            'products'   => $result['products'] ?? [],
            'total'      => $result['total'] ?? 0,
            'totalPages' => $result['total_pages'] ?? 0,
            'page'       => isset($params['page']) ? absint($params['page']) : 1,
            'perPage'    => isset($params['per_page']) ? absint($params['per_page']) : 10,
        ];

        if (isset($result['error'])) {
            $adapted['error'] = $result['error'];
        }

        if (isset($result['message'])) {
            $adapted['message'] = $result['message'];
        }

        if ($includeFilters) {
            $adapted['filters'] = $params;
        }

        return $adapted;
    }

    /**
     * Gets all product categories for filter dropdowns
     *
     * When Polylang is active, delegates language-aware term retrieval
     * and deduplication to PolylangTermHandler.
     *
     * @return array Array of categories with id, name, slug, count
     */
    public static function getCategories(): array {
        $cache_key = 'aipt_product_filter_categories';
        $cached = wp_cache_get($cache_key, 'aipt_products');

        if (false !== $cached && is_array($cached)) {
            return $cached;
        }

        $args = [
            'taxonomy'   => 'product_cat',
            'hide_empty' => false,
            'orderby'    => 'name',
            'order'      => 'ASC',
        ];

        PolylangTermHandler::adjustTermQueryArgs($args);

        $terms = get_terms($args);

        if (is_wp_error($terms)) {
            return [];
        }

        if (!is_array($terms)) {
            return [];
        }

        $terms = PolylangTermHandler::deduplicateTerms($terms);

        $categories = [];
        foreach ($terms as $term) {
            if (!is_object($term)) {
                continue;
            }
            $categories[] = [
                'id'    => $term->term_id,
                'name'  => html_entity_decode($term->name, ENT_QUOTES, 'UTF-8'),
                'slug'  => $term->slug,
                'count' => $term->count,
            ];
        }

        wp_cache_set($cache_key, $categories, 'aipt_products', 300);

        return $categories;
    }

    /**
     * Gets all product tags for filter dropdowns
     *
     * When Polylang is active, delegates language-aware term retrieval
     * and deduplication to PolylangTermHandler.
     *
     * @return array Array of tags with id, name, slug, count
     */
    public static function getTags(): array {
        $cache_key = 'aipt_product_filter_tags';
        $cached = wp_cache_get($cache_key, 'aipt_products');

        if (false !== $cached && is_array($cached)) {
            return $cached;
        }

        $args = [
            'taxonomy'   => 'product_tag',
            'hide_empty' => false,
            'orderby'    => 'name',
            'order'      => 'ASC',
        ];

        PolylangTermHandler::adjustTermQueryArgs($args);

        $terms = get_terms($args);

        if (is_wp_error($terms)) {
            return [];
        }

        if (!is_array($terms)) {
            return [];
        }

        $terms = PolylangTermHandler::deduplicateTerms($terms);

        $tags = [];
        foreach ($terms as $term) {
            if (!is_object($term)) {
                continue;
            }
            $tags[] = [
                'id'    => $term->term_id,
                'name'  => html_entity_decode($term->name, ENT_QUOTES, 'UTF-8'),
                'slug'  => $term->slug,
                'count' => $term->count,
            ];
        }

        wp_cache_set($cache_key, $tags, 'aipt_products', 300);

        return $tags;
    }

    /**
     * Register cache invalidation hooks for term changes.
     * Should be called during plugin initialization.
     *
     * @return void
     */
    public static function registerCacheInvalidationHooks(): void {

        add_action( 'created_product_cat', array( __CLASS__, 'invalidateCategoriesCache' ) );
        add_action( 'edited_product_cat', array( __CLASS__, 'invalidateCategoriesCache' ) );
        add_action( 'delete_product_cat', array( __CLASS__, 'invalidateCategoriesCache' ) );

        add_action( 'created_product_tag', array( __CLASS__, 'invalidateTagsCache' ) );
        add_action( 'edited_product_tag', array( __CLASS__, 'invalidateTagsCache' ) );
        add_action( 'delete_product_tag', array( __CLASS__, 'invalidateTagsCache' ) );
    }

    /**
     * Invalidate categories cache.
     *
     * @return void
     */
    public static function invalidateCategoriesCache(): void {
        wp_cache_delete( 'aipt_product_filter_categories', 'aipt_products' );
    }

    /**
     * Invalidate tags cache.
     *
     * @return void
     */
    public static function invalidateTagsCache(): void {
        wp_cache_delete( 'aipt_product_filter_tags', 'aipt_products' );
    }

}
