<?php

namespace FleekDash\Controllers\Analytics;

use FleekDash\Services\ResponseService;
use FleekDash\Controllers\Analytics\Traits\HasDateRangeHelpers;
use WP_REST_Request;

/**
 * Content Stats Controller (V2.2)
 *
 * Analytics endpoints for published content with chart data, summaries, and period comparisons.
 * Migrated from includes/API/real/Content/PublishedController.php
 *
 * @package FleekDash\Controllers\Analytics
 * @since 2.2.0
 */
class ContentStatsController
{
    use HasDateRangeHelpers;
    /**
     * Get published content stats with date range filtering and pagination
     *
     * @param WP_REST_Request $request
     * @return \WP_REST_Response
     */
    public function index($request)
    {
        $range_info = $this->get_date_range_info($request);
        $page = $request->get_param('page') ?: 1;
        $per_page = $request->get_param('per_page') ?: 20;

        $data = $this->getRealPublishedContent($range_info, $page, $per_page);

        return ResponseService::success($data['posts'], [
            'metadata' => [
                'total_posts' => $data['total_posts'],
                'total_pages' => $data['total_pages'],
                'current_page' => $page,
                'per_page' => $per_page,
                'date_range' => $range_info,
                'endpoint' => 'published_content_full'
            ]
        ]);
    }

    /**
     * Get chart data (time series)
     *
     * @param WP_REST_Request $request
     * @return \WP_REST_Response
     */
    public function chart($request)
    {
        $range_info = $this->get_date_range_info($request);

        $data = $this->getRealPublishedContentChart($range_info);

        // Return results in consistent format (matching comparison method)
        return new \WP_REST_Response([
            'success' => true,
            'results' => $data,
            'metadata' => [
                'date_range' => $range_info,
                'endpoint' => 'published_content_chart'
            ]
        ]);
    }

    /**
     * Get summary KPIs
     *
     * @param WP_REST_Request $request
     * @return \WP_REST_Response
     */
    public function summary($request)
    {
        $range_info = $this->get_date_range_info($request);

        $summary = $this->getRealPublishedContentSummary($range_info);

        // Return results in consistent format (matching comparison method)
        return new \WP_REST_Response([
            'success' => true,
            'results' => $summary,
            'metadata' => [
                'date_range' => $range_info,
                'endpoint' => 'published_content_summary'
            ]
        ]);
    }

    /**
     * Get period comparison data
     *
     * @param WP_REST_Request $request
     * @return \WP_REST_Response
     */
    public function comparison($request)
    {
        $range_info = $this->get_date_range_info($request);
        $comparison_type = $request->get_param('comparison_type') ?: 'previous_period';

        $comparison = $this->getRealPublishedContentComparison($range_info, $comparison_type);

        return new \WP_REST_Response([
            'success' => true,
            'results' => $comparison,
            'metadata' => [
                'date_range' => $range_info,
                'comparison_type' => $comparison_type,
                'endpoint' => 'published_content_comparison'
            ]
        ]);
    }

    /**
     * Public post types used for “content” analytics (excludes pages, attachments, etc.).
     *
     * @return array<int, string>
     */
    private function getAllowedContentPostTypes(): array
    {
        $excluded_types = ['page', 'profile', 'elementor_library', 'attachment', 'e-floating-buttons'];
        $post_types = \get_post_types(['public' => true], 'names');

        return array_values(array_diff($post_types, $excluded_types));
    }

    /**
     * @param array<string, mixed> $range_info
     * @return array<int, array<string, mixed>>
     */
    private function buildPublishedPostsDateQuery(array $range_info): array
    {
        if ($range_info['start_date'] && $range_info['end_date']) {
            return [
                [
                    'after' => $range_info['start_date'],
                    'before' => $range_info['end_date'],
                    'inclusive' => true,
                ]
            ];
        }

        return [
            [
                'after' => $range_info['days'] . ' days ago',
                'inclusive' => true,
            ]
        ];
    }

    /**
     * @param array<string, mixed> $range_info
     */
    private function resolveChartStartDate(array $range_info): string
    {
        if (!empty($range_info['start_date'])) {
            return $range_info['start_date'];
        }
        if (!empty($range_info['days'])) {
            return date('Y-m-d', strtotime("-{$range_info['days']} days"));
        }

        return date('Y-m-01');
    }

    /**
     * @param array<string, mixed> $range_info
     */
    private function resolveChartEndDate(array $range_info): string
    {
        return !empty($range_info['end_date']) ? $range_info['end_date'] : date('Y-m-d');
    }

    private function trendFromNumericChange(float $change): string
    {
        if ($change > 0) {
            return 'up';
        }
        if ($change < 0) {
            return 'down';
        }

        return 'stable';
    }

    /**
     * @return array<string, mixed>
     */
    private function buildPublishedPostEntry(int $post_id): array
    {
        $post_type = \get_post_type($post_id);

        $categories = [];
        $category_name = '';
        $category_id = 0;
        if (is_object_in_taxonomy($post_type, 'category')) {
            $categories = \get_the_category($post_id);
            $category_name = !empty($categories) ? $categories[0]->name : '';
            $category_id = !empty($categories) ? $categories[0]->term_id : 0;
        }

        $tags = [];
        if (is_object_in_taxonomy($post_type, 'post_tag')) {
            $tags = \wp_get_post_tags($post_id, ['fields' => 'names']);
        }

        $author_id = \get_the_author_meta('ID');
        $author_name = \get_the_author();

        $content = \get_post_field('post_content', $post_id);
        $reading_time = $this->calculateReadingTime($content);

        return [
            'id' => $post_id,
            'title' => \get_the_title(),
            'slug' => \get_post_field('post_name', $post_id),
            'post_type' => $post_type,
            'content' => $content,
            'excerpt' => \get_the_excerpt(),
            'author' => $author_name,
            'author_id' => $author_id,
            'category' => $category_name,
            'category_id' => $category_id,
            'status' => \call_user_func('get_post_status', $post_id),
            'publish_date' => \get_the_date('Y-m-d'),
            'modified_date' => \call_user_func('get_post_modified_time', 'Y-m-d', false, $post_id, true),
            'comment_count' => (int) \call_user_func('get_comments_number', $post_id),
            'view_count' => (int) \get_post_meta($post_id, 'view_count', true),
            'featured_image' => \get_the_post_thumbnail_url($post_id, 'medium'),
            'tags' => $tags,
            'meta' => [
                'seo_title' => \get_post_meta($post_id, '_yoast_wpseo_title', true),
                'seo_description' => \get_post_meta($post_id, '_yoast_wpseo_metadesc', true),
                'reading_time' => $reading_time . ' min read'
            ]
        ];
    }

    /**
     * @param array<string, mixed> $range_info
     * @return array{posts: array<int, array<string, mixed>>, total_posts: int, total_pages: int}
     */
    private function getRealPublishedContent($range_info, $page = 1, $per_page = 20)
    {
        $allowed_post_types = $this->getAllowedContentPostTypes();
        $date_query = $this->buildPublishedPostsDateQuery($range_info);

        $args = [
            'post_type' => $allowed_post_types,
            'post_status' => 'publish',
            'posts_per_page' => $per_page,
            'paged' => $page,
            'date_query' => $date_query,
            'orderby' => 'date',
            'order' => 'DESC',
            'update_post_meta_cache' => false,
            'update_post_term_cache' => false,
            'ignore_sticky_posts' => true,
        ];

        $query = new \WP_Query($args);
        $posts = [];

        if ($query->have_posts()) {
            while ($query->have_posts()) {
                $query->the_post();
                $posts[] = $this->buildPublishedPostEntry(\get_the_ID());
            }
        }
        wp_reset_postdata();

        return [
            'posts' => $posts,
            'total_posts' => $query->found_posts,
            'total_pages' => $query->max_num_pages
        ];
    }

    /**
     * @param array<string, mixed> $range_info
     * @return array<int, array<string, mixed>>
     */
    private function getRealPublishedContentChart($range_info)
    {
        global $wpdb;

        $start_date = $this->resolveChartStartDate($range_info);
        $end_date = $this->resolveChartEndDate($range_info);

        $allowed_post_types = $this->getAllowedContentPostTypes();

        // Create placeholders for the IN clause
        $placeholders = implode(',', array_fill(0, count($allowed_post_types), '%s'));

        $query = $wpdb->prepare("
            SELECT
                DATE(post_date) as date,
                COUNT(*) as published_posts,
                SUM(LENGTH(post_content)) as total_words,
                AVG(LENGTH(post_content) / 200) as avg_reading_time,
                AVG(COALESCE(meta_value, 0)) as engagement_rate
            FROM {$wpdb->posts} p
            LEFT JOIN {$wpdb->postmeta} pm ON p.ID = pm.post_id AND pm.meta_key = 'engagement_rate'
            WHERE p.post_type IN ({$placeholders})
            AND p.post_status = 'publish'
            AND DATE(p.post_date) BETWEEN %s AND %s
            GROUP BY DATE(post_date)
            ORDER BY date ASC
        ", array_merge($allowed_post_types, [$start_date, $end_date]));

        $results = $wpdb->get_results($query, ARRAY_A);

        // Format results
        $chart_data = [];
        foreach ($results as $row) {
            $chart_data[] = [
                'date' => $row['date'],
                'published_posts' => (int) $row['published_posts'],
                'total_words' => (int) $row['total_words'],
                'avg_reading_time' => round((float) $row['avg_reading_time'], 1),
                'engagement_rate' => round((float) $row['engagement_rate'], 2)
            ];
        }

        return $chart_data;
    }

    /**
     * @param array<string, mixed> $range_info
     * @return array<string, mixed>
     */
    private function getRealPublishedContentSummary($range_info)
    {
        global $wpdb;

        $start_date = $range_info['start_date'] ?: date('Y-m-d', strtotime("-{$range_info['days']} days"));
        $end_date = $range_info['end_date'] ?: date('Y-m-d');

        $allowed_post_types = $this->getAllowedContentPostTypes();

        // Create placeholders for the IN clause
        $placeholders = implode(',', array_fill(0, count($allowed_post_types), '%s'));

        // Get total posts
        $total_posts = $wpdb->get_var($wpdb->prepare("
            SELECT COUNT(*) FROM {$wpdb->posts}
            WHERE post_type IN ({$placeholders})
            AND post_status = 'publish'
            AND DATE(post_date) BETWEEN %s AND %s
        ", array_merge($allowed_post_types, [$start_date, $end_date])));

        // Get total words
        $total_words = $wpdb->get_var($wpdb->prepare("
            SELECT SUM(LENGTH(post_content)) FROM {$wpdb->posts}
            WHERE post_type IN ({$placeholders})
            AND post_status = 'publish'
            AND DATE(post_date) BETWEEN %s AND %s
        ", array_merge($allowed_post_types, [$start_date, $end_date])));

        // Get average reading time
        $avg_reading_time = $wpdb->get_var($wpdb->prepare("
            SELECT AVG(LENGTH(post_content) / 200) FROM {$wpdb->posts}
            WHERE post_type IN ({$placeholders})
            AND post_status = 'publish'
            AND DATE(post_date) BETWEEN %s AND %s
        ", array_merge($allowed_post_types, [$start_date, $end_date])));

        // Get average engagement rate
        $avg_engagement = $wpdb->get_var($wpdb->prepare("
            SELECT AVG(meta_value) FROM {$wpdb->postmeta} pm
            JOIN {$wpdb->posts} p ON pm.post_id = p.ID
            WHERE pm.meta_key = 'engagement_rate'
            AND p.post_type IN ({$placeholders})
            AND p.post_status = 'publish'
            AND DATE(p.post_date) BETWEEN %s AND %s
        ", array_merge($allowed_post_types, [$start_date, $end_date])));

        // Get top categories (only for post types that support categories)
        $top_categories = $wpdb->get_results($wpdb->prepare("
            SELECT t.name, COUNT(*) as count
            FROM {$wpdb->posts} p
            JOIN {$wpdb->term_relationships} tr ON p.ID = tr.object_id
            JOIN {$wpdb->term_taxonomy} tt ON tr.term_taxonomy_id = tt.term_taxonomy_id
            JOIN {$wpdb->terms} t ON tt.term_id = t.term_id
            WHERE p.post_type IN ({$placeholders})
            AND p.post_status = 'publish'
            AND tt.taxonomy = 'category'
            AND DATE(p.post_date) BETWEEN %s AND %s
            GROUP BY t.term_id
            ORDER BY count DESC
            LIMIT 5
        ", array_merge($allowed_post_types, [$start_date, $end_date]), ARRAY_A));

        // Get top authors
        $top_authors = $wpdb->get_results($wpdb->prepare("
            SELECT u.display_name as name, COUNT(*) as posts
            FROM {$wpdb->posts} p
            JOIN {$wpdb->users} u ON p.post_author = u.ID
            WHERE p.post_type IN ({$placeholders})
            AND p.post_status = 'publish'
            AND DATE(p.post_date) BETWEEN %s AND %s
            GROUP BY p.post_author
            ORDER BY posts DESC
            LIMIT 5
        ", array_merge($allowed_post_types, [$start_date, $end_date]), ARRAY_A));

        $days = $range_info['days'];

        return [
            'total_published_posts' => (int) $total_posts,
            'total_words_written' => (int) $total_words,
            'average_reading_time' => round((float) $avg_reading_time, 1),
            'engagement_rate' => round((float) $avg_engagement, 2),
            'posts_per_day' => $total_posts > 0 ? round($total_posts / $days, 1) : 0,
            'words_per_day' => $total_words > 0 ? round($total_words / $days, 0) : 0,
            'top_categories' => $top_categories,
            'top_authors' => $top_authors
        ];
    }

    /**
     * @param array<string, mixed> $range_info
     * @return array<string, mixed>
     */
    private function getRealPublishedContentComparison($range_info, $comparison_type)
    {
        // Get comparison dates
        $comparison_dates = $this->get_comparison_dates($range_info, $comparison_type);

        // Get current period data
        $current_chart_data = $this->getRealPublishedContentChart($range_info);
        $current_summary = $this->getRealPublishedContentSummary($range_info);

        // Get comparison period data
        $comparison_range_info = [
            'days' => $comparison_dates['days'],
            'start_date' => $comparison_dates['start_date'],
            'end_date' => $comparison_dates['end_date']
        ];
        $comparison_chart_data = $this->getRealPublishedContentChart($comparison_range_info);
        $comparison_summary = $this->getRealPublishedContentSummary($comparison_range_info);

        // Calculate comparison metrics
        $comparison_metrics = $this->calculateRealComparisonMetrics($current_chart_data, $comparison_chart_data);

        return [
            'current_period' => [
                'data' => $current_chart_data,
                'summary' => $current_summary
            ],
            'comparison_period' => [
                'data' => $comparison_chart_data,
                'summary' => $comparison_summary
            ],
            'comparison_metrics' => $comparison_metrics,
            'comparison_type' => $comparison_type,
            'period_dates' => [
                'current' => [
                    'start_date' => $range_info['start_date'] ?: date('Y-m-d', strtotime("-{$range_info['days']} days")),
                    'end_date' => $range_info['end_date'] ?: date('Y-m-d')
                ],
                'comparison' => [
                    'start_date' => $comparison_dates['start_date'],
                    'end_date' => $comparison_dates['end_date']
                ]
            ]
        ];
    }

    /**
     * @param array<int, array<string, mixed>> $current_data
     * @param array<int, array<string, mixed>> $comparison_data
     * @return array<string, array<string, float|int|string>>
     */
    private function calculateRealComparisonMetrics($current_data, $comparison_data)
    {
        $current_total_posts = array_sum(array_column($current_data, 'published_posts'));
        $comparison_total_posts = array_sum(array_column($comparison_data, 'published_posts'));

        $current_total_words = array_sum(array_column($current_data, 'total_words'));
        $comparison_total_words = array_sum(array_column($comparison_data, 'total_words'));

        $current_avg_engagement = array_sum(array_column($current_data, 'engagement_rate')) / max(count($current_data), 1);
        $comparison_avg_engagement = array_sum(array_column($comparison_data, 'engagement_rate')) / max(count($comparison_data), 1);

        $posts_change = $current_total_posts - $comparison_total_posts;
        $posts_change_percentage = $comparison_total_posts > 0 ? ($posts_change / $comparison_total_posts) * 100 : 0;

        $words_change = $current_total_words - $comparison_total_words;
        $words_change_percentage = $comparison_total_words > 0 ? ($words_change / $comparison_total_words) * 100 : 0;

        $engagement_change = $current_avg_engagement - $comparison_avg_engagement;
        $engagement_change_percentage = $comparison_avg_engagement > 0 ? ($engagement_change / $comparison_avg_engagement) * 100 : 0;

        return [
            'published_posts' => [
                'current' => $current_total_posts,
                'previous' => $comparison_total_posts,
                'change' => $posts_change,
                'change_percentage' => round($posts_change_percentage, 2),
                'trend' => $this->trendFromNumericChange((float) $posts_change)
            ],
            'total_words' => [
                'current' => $current_total_words,
                'previous' => $comparison_total_words,
                'change' => $words_change,
                'change_percentage' => round($words_change_percentage, 2),
                'trend' => $this->trendFromNumericChange((float) $words_change)
            ],
            'engagement_rate' => [
                'current' => round($current_avg_engagement * 100, 1),
                'previous' => round($comparison_avg_engagement * 100, 1),
                'change' => round($engagement_change * 100, 1),
                'change_percentage' => round($engagement_change_percentage, 2),
                'trend' => $this->trendFromNumericChange((float) $engagement_change)
            ]
        ];
    }

    private function calculateReadingTime($content)
    {
        $word_count = str_word_count(strip_tags($content));
        $reading_time = ceil($word_count / 200);

        return max(1, $reading_time);
    }
}
