<?php

namespace NewsletterBridge\Services\Query;

use NewsletterBridge\Interfaces\QueryBuilderInterface;
use NewsletterBridge\Services\Query\DateRangeBuilder;
use NewsletterBridge\Services\Query\TaxonomyQueryBuilder;
use NewsletterBridge\Services\Post\NewsletterPostFields;

/**
 * Responsabilità: Costruzione delle query WordPress
 * Single Responsibility: Solo logica di costruzione query
 * Refactored: Usa composizione per separare responsabilità
 */
class QueryBuilder implements QueryBuilderInterface {
    
    private DateRangeBuilder $dateRangeBuilder;
    private TaxonomyQueryBuilder $taxonomyBuilder;
    private array $baseArgs;
    
    public function __construct(
        DateRangeBuilder $dateRangeBuilder,
        TaxonomyQueryBuilder $taxonomyBuilder
    ) {
        $this->dateRangeBuilder = $dateRangeBuilder;
        $this->taxonomyBuilder = $taxonomyBuilder;
        $this->baseArgs = $this->getBaseQueryArgs();
    }
    
    /**
     * Costruisce gli argomenti base per le query
     */
    private function getBaseQueryArgs(): array {
        return [
            'post_status'    => 'publish',
            'post_type'      => ['post'],
            'date_query'     => [
                $this->dateRangeBuilder->buildDateRange()
            ]
        ];
    }
    
    /**
     * Costruisce una query completa per un feed specifico
     */
    public function buildQuery(string $feed_name, array $feed_config, array $used_posts = []): array {
        $args = $this->baseArgs;
        
        if (isset($feed_config['query_params'])) {
            $args = $this->applyFeedParams($args, $this->normalizeQueryParamsObject($feed_config['query_params']));
        }
        
        // Esclude post già utilizzati
        if (!empty($used_posts)) {
            $args['post__not_in'] = $used_posts;
        }
        
        return $args;
    }
    
    /**
     * @param array<string, mixed>|object|null $query_params
     */
    private function normalizeQueryParamsObject($query_params): \stdClass {
        if ($query_params === null) {
            return new \stdClass();
        }
        if ($query_params instanceof \stdClass) {
            return $query_params;
        }
        if (is_array($query_params)) {
            return json_decode(json_encode($query_params)) ?: new \stdClass();
        }
        return new \stdClass();
    }

    /**
     * Applica i parametri specifici del feed alla query
     */
    private function applyFeedParams(array $args, \stdClass $query_params): array {
        // Posts per page
        if (isset($query_params->posts_per_page)) {
            $args['posts_per_page'] = $query_params->posts_per_page;
        }
        
        // Post types (ignora array vuoto: altrimenti sovrascrive il default e la query non restituisce nulla)
        $post_types = self::normalizePostTypes($query_params->post_types ?? null);
        if ($post_types !== null) {
            $args['post_type'] = count($post_types) === 1 ? $post_types[0] : $post_types;
        }
        
        // Tassonomie da includere
        $include_taxonomies = $query_params->include_taxonomies ?? $query_params->include_tags ?? null;
        if ($include_taxonomies) {
            // Converte stdClass in array se necessario
            if (is_object($include_taxonomies)) {
                $include_taxonomies = (array) $include_taxonomies;
            }
            // Assicura che sia un array
            if (!is_array($include_taxonomies)) {
                $include_taxonomies = [$include_taxonomies];
            }
            
            $include_query = $this->taxonomyBuilder->buildIncludeQuery($include_taxonomies);
            if (!empty($include_query)) {
                $args['tax_query'] = $this->taxonomyBuilder->combineTaxQueries($args['tax_query'] ?? [], $include_query);
            }
        }
        
        // Tassonomie da escludere
        $exclude_taxonomies = $query_params->exclude_taxonomies ?? $query_params->exclude_tags ?? null;
        if ($exclude_taxonomies) {
            // Converte stdClass in array se necessario
            if (is_object($exclude_taxonomies)) {
                $exclude_taxonomies = (array) $exclude_taxonomies;
            }
            // Assicura che sia un array
            if (!is_array($exclude_taxonomies)) {
                $exclude_taxonomies = [$exclude_taxonomies];
            }
            
            $exclude_query = $this->taxonomyBuilder->buildExcludeQuery($exclude_taxonomies);
            if (!empty($exclude_query)) {
                $args['tax_query'] = $this->taxonomyBuilder->combineTaxQueries($args['tax_query'] ?? [], $exclude_query);
            }
        }
        
        // Meta query personalizzata (da configurazione feed JSON)
        if (isset($query_params->meta_query)) {
            $existing = $args['meta_query'] ?? [];
            $args['meta_query'] = array_merge($existing, (array) $query_params->meta_query);
        }

        // only | exclude: filtro rigido. prioritize (o vuoto): gestito in FeedGenerator con due query.
        $in_evidenza_filter = (string) ($query_params->in_evidenza_filter ?? '');
        if (in_array($in_evidenza_filter, ['only', 'exclude'], true)) {
            $args = self::applyInEvidenzaFilter($args, $in_evidenza_filter);
        }
        
        return $args;
    }

    /**
     * Priorità in evidenza: prima gli articoli flaggati, poi il resto fino al limite.
     */
    public static function usesInEvidenzaPriority(string $filter): bool {
        return $filter === 'prioritize' || $filter === '';
    }

    /**
     * Applica filtro meta in_evidenza (only | exclude).
     */
    public static function applyInEvidenzaFilter(array $args, string $filter): array {
        if (!in_array($filter, ['only', 'exclude'], true)) {
            return $args;
        }

        $evidenza_clause = NewsletterPostFields::buildInEvidenzaMetaQuery($filter);
        if ($evidenza_clause === null) {
            return $args;
        }

        $meta_query = $args['meta_query'] ?? [];
        if ($meta_query !== [] && !isset($meta_query['relation'])) {
            $meta_query = array_merge(['relation' => 'AND'], $meta_query);
        }

        foreach ($evidenza_clause as $clause) {
            $meta_query[] = $clause;
        }

        $args['meta_query'] = $meta_query;

        return $args;
    }

    /**
     * @return string[]|null Elenco post type oppure null per lasciare il default della query base.
     */
    private static function normalizePostTypes($post_types): ?array {
        if ($post_types === null) {
            return null;
        }

        if (is_object($post_types)) {
            $post_types = (array) $post_types;
        }
        if (!is_array($post_types)) {
            $post_types = [$post_types];
        }

        $normalized = array_values(array_filter(array_map('sanitize_key', $post_types)));

        return $normalized !== [] ? $normalized : null;
    }
}
