<?php

namespace NewsletterBridge\Services\Feed;

use NewsletterBridge\Services\Query\QueryBuilder;
use NewsletterBridge\Services\Query\PostExclusionManager;
use NewsletterBridge\Services\Content\PostTemplateProcessor;
use NewsletterBridge\Services\Feed\RSSFormatter;
use NewsletterBridge\Services\Post\NewsletterPostFields;

/**
 * Responsabilità: Generazione feed newsletter
 * Single Responsibility: Orchestrazione generazione feed
 */
class FeedGenerator {

    /** @var array<int, array{feed: string, step: string, args: array<string, mixed>, posts_found: int}> */
    private array $queryLog = [];

    private bool $logQueries = false;

    private ?string $currentFeedName = null;
    
    private QueryBuilder $queryBuilder;
    private PostExclusionManager $exclusionManager;
    private PostTemplateProcessor $templateProcessor;
    private RSSFormatter $rssFormatter;
    private XMLFileManager $xmlFileManager;
    
    public function __construct(
        QueryBuilder $queryBuilder,
        PostExclusionManager $exclusionManager,
        PostTemplateProcessor $templateProcessor,
        RSSFormatter $rssFormatter,
        XMLFileManager $xmlFileManager
    ) {
        $this->queryBuilder = $queryBuilder;
        $this->exclusionManager = $exclusionManager;
        $this->templateProcessor = $templateProcessor;
        $this->rssFormatter = $rssFormatter;
        $this->xmlFileManager = $xmlFileManager;
    }
    
    /**
     * Genera tutti i feed in una singola chiamata
     */
    public function enableQueryLogging(bool $enable = true): void {
        $this->logQueries = $enable;
        if ($enable) {
            $this->queryLog = [];
        }
    }

    /**
     * @return array<int, array{feed: string, step: string, args: array<string, mixed>, posts_found: int}>
     */
    public function getQueryLog(): array {
        return $this->queryLog;
    }

    public function generateAllFeeds(\stdClass $config, bool $preview = false, int $site_id = null): array {
        $feeds = [];
        
        // Genera i feed di sistema
        $feeds['subject'] = $this->generateSingleFeed('subject', $config, $preview);
        
        // Genera i feed configurati
        foreach ($config->feeds as $feed) {
            $feed_name = $feed->name ?? 'unknown';
            $feeds[$feed_name] = $this->generateSingleFeed($feed_name, $config, $preview);
        }
        
        // Se non è preview, salva i file XML
        if (!$preview) {
            $this->xmlFileManager->generateFiles($feeds, $config->feeds, $site_id);
        }
        
        return $feeds;
    }
    
    /**
     * Genera un singolo feed
     */
    public function generateSingleFeed(string $feed_name, \stdClass $config, bool $preview = false): string {
        // Gestione speciale per il feed subject
        if ($feed_name === 'subject') {
            return $this->generateSubjectFeed($config);
        }

        $this->currentFeedName = $feed_name;
        
        $used_posts = $this->exclusionManager->getUsedPosts();
        $feed_config = $this->getFeedConfig($feed_name, $config);
        
        if (!$feed_config) {
            return $this->rssFormatter->formatRSS([]);
        }
        
        $query_params = $this->normalizeQueryParams($feed_config['query_params'] ?? null);
        $query_args = $this->queryBuilder->buildQuery($feed_name, $feed_config, $used_posts);
        $posts = $this->fetchPostsForFeed($query_args, $query_params);
        
        // Processa i post in template
        $template_posts = $this->templateProcessor->processPosts($posts);
        
        // Marca i post come utilizzati
        foreach ($template_posts as $post) {
            $this->exclusionManager->markPostAsUsed($post->id);
        }
        
        // Salva i post utilizzati
        $this->exclusionManager->saveUsedPosts();
        
        // Genera il feed RSS
        $this->currentFeedName = null;

        return $this->rssFormatter->formatRSS($template_posts);
    }
    
    /**
     * Genera il feed subject: titolo fisso da configurazione oppure dal primo post del primo feed.
     */
    private function generateSubjectFeed(\stdClass $config): string {
        $title = '';

        if (!empty($config->newsletter_title_from_featured)) {
            $fromPost = $this->getTitleFromFirstFeedPost($config);
            if ($fromPost !== null && $fromPost !== '') {
                $title = $this->replaceDatePlaceholder($fromPost);
            }
        }

        if ($title === '') {
            $base = $config->newsletter_title ?? 'Newsletter {{date}}';
            $title = $this->replaceDatePlaceholder($base);
        }

        $virtual_post = (object) [
            'id' => 'subject_' . time(),
            'title' => $title,
            'content' => '',
            'excerpt' => '',
            'date' => date('Y-m-d H:i:s'),
            'author' => 'Newsletter System',
            'url' => get_home_url(),
            'image' => ''
        ];

        return $this->rssFormatter->formatRSS([$virtual_post]);
    }

    /**
     * Titolo dal primo post del primo feed: se in evidenza usa oggetto newsletter, altrimenti titolo articolo.
     */
    private function getTitleFromFirstFeedPost(\stdClass $config): ?string {
        if (empty($config->feeds)) {
            return null;
        }

        $first = $config->feeds[0];
        $feed_name = is_object($first) ? ($first->name ?? '') : ($first['name'] ?? '');
        if ($feed_name === '') {
            return null;
        }

        $feed_config = $this->getFeedConfig($feed_name, $config);
        if ($feed_config === null) {
            return null;
        }

        $query_params = $this->normalizeQueryParams($feed_config['query_params'] ?? null);
        $query_args = $this->queryBuilder->buildQuery($feed_name, $feed_config, []);
        $posts = $this->fetchPostsForFeed($query_args, $query_params);
        if (empty($posts)) {
            return null;
        }

        $title = NewsletterPostFields::resolveNewsletterTitle((int) $posts[0]->ID);
        return $title !== '' ? $title : null;
    }
    
    /**
     * Sostituisce il placeholder {{date}} con la data italiana
     */
    private function replaceDatePlaceholder(string $text): string {
        $months = [
            1 => 'gennaio', 2 => 'febbraio', 3 => 'marzo', 4 => 'aprile',
            5 => 'maggio', 6 => 'giugno', 7 => 'luglio', 8 => 'agosto',
            9 => 'settembre', 10 => 'ottobre', 11 => 'novembre', 12 => 'dicembre'
        ];
        
        $day = date('j');
        $month = $months[(int)date('n')];
        $year = date('Y');
        
        $italian_date = "$day $month $year";
        
        return str_replace('{{date}}', $italian_date, $text);
    }
    
    /**
     * Ottiene la configurazione di un feed
     */
    private function getFeedConfig(string $feed_name, \stdClass $config): ?array {
        if ($feed_name === 'summary') {
            return null; // Feed summary eliminato
        }
        
        foreach ($config->feeds as $feed) {
            if ($feed->name === $feed_name) {
                return (array)$feed;
            }
        }
        
        return null;
    }
    
    /**
     * Resetta i post utilizzati
     */
    public function resetUsedPosts(): void {
        $this->exclusionManager->resetUsedPosts();
    }

    /**
     * @param array<string, mixed> $feed_config
     */
    private function normalizeQueryParams($query_params): \stdClass {
        if ($query_params === null) {
            return new \stdClass();
        }
        if (is_array($query_params)) {
            return json_decode(json_encode($query_params)) ?: new \stdClass();
        }
        if ($query_params instanceof \stdClass) {
            return $query_params;
        }
        return new \stdClass();
    }

    /**
     * Esegue la query del feed (con priorità in evidenza se configurato).
     *
     * @param array<string, mixed> $query_args
     */
    private function fetchPostsForFeed(array $query_args, \stdClass $query_params): array {
        $filter = (string) ($query_params->in_evidenza_filter ?? '');

        if (QueryBuilder::usesInEvidenzaPriority($filter)) {
            return $this->fetchPostsWithInEvidenzaPriority($query_args);
        }

        $posts = get_posts($query_args);
        $this->recordQuery('query principale', $query_args, count($posts));

        return $posts;
    }

    /**
     * Articoli in evidenza per primi, poi gli altri fino a posts_per_page.
     *
     * @param array<string, mixed> $base_args
     * @return \WP_Post[]
     */
    private function fetchPostsWithInEvidenzaPriority(array $base_args): array {
        $limit = max(1, (int) ($base_args['posts_per_page'] ?? 10));

        $featured_args = QueryBuilder::applyInEvidenzaFilter($base_args, 'only');
        $featured_args['posts_per_page'] = $limit;
        $featured_posts = get_posts($featured_args);
        $this->recordQuery('in evidenza (priorità)', $featured_args, count($featured_posts));

        $featured_ids = array_map(static fn ($post) => (int) $post->ID, $featured_posts);
        $remaining = $limit - count($featured_posts);

        if ($remaining <= 0) {
            return $featured_posts;
        }

        $rest_args = $base_args;
        $rest_args['posts_per_page'] = $remaining;

        $not_in = array_merge((array) ($base_args['post__not_in'] ?? []), $featured_ids);
        $rest_args['post__not_in'] = array_values(array_unique(array_filter($not_in)));

        $rest_args = QueryBuilder::applyInEvidenzaFilter($rest_args, 'exclude');
        $rest_posts = get_posts($rest_args);
        $this->recordQuery('complemento (priorità)', $rest_args, count($rest_posts));

        return array_merge($featured_posts, $rest_posts);
    }

    /**
     * @param array<string, mixed> $args
     */
    private function recordQuery(string $step, array $args, int $posts_found): void {
        if (!$this->logQueries || $this->currentFeedName === null) {
            return;
        }

        $this->queryLog[] = [
            'feed' => $this->currentFeedName,
            'step' => $step,
            'args' => $args,
            'posts_found' => $posts_found,
        ];
    }
}
