<?php

namespace FleekDash\Controllers\Analytics;

// Load debug helpers
if (!function_exists('fleekdash_log_error')) {
    require_once FLEEKDASH_PLUGIN_DIR . 'includes/Core/debug-helpers.php';
}

use FleekDash\Services\AnalyticsTrackingService;

/**
 * Analytics Calculator
 *
 * Handles all calculation logic for analytics
 *
 * @package FleekDash\Controllers\Analytics
 */
class AnalyticsCalculator
{
    private $trackingService;

    public function __construct()
    {
        $this->trackingService = AnalyticsTrackingService::getInstance();
    }

    /**
     * Calculate visitors data for date range
     *
     * @param array $date_range Date range with start and end
     * @param string $aggregation Aggregation type
     * @return array Visitors data
     */
    public function calculateVisitorsData($date_range, $aggregation)
    {
        try {
            $real_data = $this->trackingService->getVisitorsData(
                $date_range['start'],
                $date_range['end'],
                $aggregation
            );

            if (!empty($real_data)) {
                return $real_data;
            }

            // Fallback to empty data
            return [];

        } catch (\Exception $e) {
            fleekdash_log_error("FleekDash: Visitors calculation error: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Calculate pageviews data for date range
     *
     * @param array $date_range Date range
     * @param string $aggregation Aggregation type
     * @return array Pageviews data
     */
    public function calculatePageviewsData($date_range, $aggregation)
    {
        try {
            $real_data = $this->trackingService->getPageviewsData(
                $date_range['start'],
                $date_range['end'],
                $aggregation
            );

            if (!empty($real_data)) {
                return $real_data;
            }

            return [];

        } catch (\Exception $e) {
            fleekdash_log_error("FleekDash: Pageviews calculation error: " . $e->getMessage());
            return [];
        }
    }

    /**
     * Calculate KPI summary
     *
     * @param array $date_range Date range
     * @return array KPI summary
     */
    public function calculateKPISummary($date_range)
    {
        $current_start = $date_range['start'];
        $current_end = $date_range['end'];

        $period_length = $current_end->diff($current_start)->days;
        $previous_start = clone $current_start;
        $previous_start->modify("-{$period_length} days");
        $previous_end = clone $current_start;
        $previous_end->modify('-1 day');

        // Calculate visitors
        $visitors_current = $this->getPeriodVisitors($current_start, $current_end);
        $visitors_previous = $this->getPeriodVisitors($previous_start, $previous_end);

        // Calculate pageviews
        $pageviews_current = $this->getPeriodPageviews($current_start, $current_end);
        $pageviews_previous = $this->getPeriodPageviews($previous_start, $previous_end);

        // Calculate bounce rate
        $bounce_current = $this->getPeriodBounceRate($current_start, $current_end);
        $bounce_previous = $this->getPeriodBounceRate($previous_start, $previous_end);

        // Calculate session duration
        $session_current = $this->getPeriodSessionDuration($current_start, $current_end);
        $session_previous = $this->getPeriodSessionDuration($previous_start, $previous_end);

        // Calculate new users
        $new_users_current = $this->getPeriodNewUsersPercentage($current_start, $current_end);
        $new_users_previous = $this->getPeriodNewUsersPercentage($previous_start, $previous_end);

        // Calculate posts per day
        $posts_current = $this->getAveragePostsPerDay($current_start, $current_end);
        $posts_previous = $this->getAveragePostsPerDay($previous_start, $previous_end);

        return [
            'visitors' => [
                'current' => $visitors_current,
                'previous' => $visitors_previous,
                'change_percentage' => $this->calculateChangePercentage($visitors_previous, $visitors_current)
            ],
            'pageviews' => [
                'current' => $pageviews_current,
                'previous' => $pageviews_previous,
                'change_percentage' => $this->calculateChangePercentage($pageviews_previous, $pageviews_current)
            ],
            'bounce_rate' => [
                'current' => $bounce_current,
                'previous' => $bounce_previous,
                'change_percentage' => $this->calculateChangePercentage($bounce_previous, $bounce_current)
            ],
            'session_duration' => [
                'current' => $session_current,
                'previous' => $session_previous,
                'change_percentage' => $this->calculateChangePercentage($session_previous, $session_current)
            ],
            'new_users' => [
                'current' => $new_users_current,
                'previous' => $new_users_previous,
                'change_percentage' => $this->calculateChangePercentage($new_users_previous, $new_users_current)
            ],
            'posts_per_day' => [
                'current' => $posts_current,
                'previous' => $posts_previous,
                'change_percentage' => $this->calculateChangePercentage($posts_previous, $posts_current)
            ]
        ];
    }

    /**
     * Calculate percentage change between two values
     *
     * @param float $previous Previous period value
     * @param float $current Current period value
     * @return float Percentage change (positive or negative)
     */
    private function calculateChangePercentage($previous, $current)
    {
        // If previous is 0, handle edge case
        if ($previous == 0) {
            if ($current == 0) {
                return 0; // No change
            }
            return 100; // 100% increase from zero
        }

        // Calculate percentage change
        $change = (($current - $previous) / $previous) * 100;
        return round($change, 1);
    }

    /**
     * Get posts count for specific date
     *
     * @param \DateTime $date Date
     * @return int Posts count
     */
    public function getPostsCountForDate($date)
    {
        static $memo = [];
        $key = $date->format('Y-m-d');
        if (isset($memo[$key])) {
            return $memo[$key];
        }

        $count = \get_posts([
            'numberposts' => -1,
            'post_status' => 'publish',
            'fields' => 'ids',
            'date_query' => [
                [
                    'year' => $date->format('Y'),
                    'month' => $date->format('m'),
                    'day' => $date->format('d')
                ]
            ],
            'no_found_rows' => true,
            'update_post_meta_cache' => false,
            'update_post_term_cache' => false,
            'ignore_sticky_posts' => true,
            'cache_results' => false,
        ]);

        $result = is_array($count) ? count($count) : 0;
        $memo[$key] = $result;
        return $result;
    }

    /**
     * Get comments count for specific date
     *
     * @param \DateTime $date Date
     * @return int Comments count
     */
    public function getCommentsCountForDate($date)
    {
        static $memo = [];
        $key = $date->format('Y-m-d');
        if (isset($memo[$key])) {
            return $memo[$key];
        }

        $comments_count = \get_comments([
            'status' => 'approve',
            'date_query' => [
                [
                    'year' => $date->format('Y'),
                    'month' => $date->format('m'),
                    'day' => $date->format('d')
                ]
            ],
            'count' => true,
        ]);

        $result = (int) $comments_count;
        $memo[$key] = $result;
        return $result;
    }

    /**
     * Get visitors for a period
     */
    public function getPeriodVisitors($start, $end)
    {
        global $wpdb;

        $table_pageviews = $wpdb->prefix . 'fleekdash_pageviews';

        if ($wpdb->get_var("SHOW TABLES LIKE '$table_pageviews'") == $table_pageviews) {
            $visitors = $wpdb->get_var($wpdb->prepare("
                SELECT COUNT(DISTINCT session_id)
                FROM $table_pageviews
                WHERE DATE(viewed_at) BETWEEN %s AND %s
            ", $start->format('Y-m-d'), $end->format('Y-m-d')));

            if ($visitors > 0) {
                return (int) $visitors;
            }
        }

        return 0;
    }

    /**
     * Get pageviews for a period
     */
    public function getPeriodPageviews($start, $end)
    {
        global $wpdb;

        $table_pageviews = $wpdb->prefix . 'fleekdash_pageviews';

        if ($wpdb->get_var("SHOW TABLES LIKE '$table_pageviews'") == $table_pageviews) {
            $pageviews = $wpdb->get_var($wpdb->prepare("
                SELECT COUNT(*)
                FROM $table_pageviews
                WHERE DATE(viewed_at) BETWEEN %s AND %s
            ", $start->format('Y-m-d'), $end->format('Y-m-d')));

            if ($pageviews > 0) {
                return (int) $pageviews;
            }
        }

        return 0;
    }

    /**
     * Get bounce rate for a period
     */
    public function getPeriodBounceRate($start, $end)
    {
        global $wpdb;

        $table_sessions = $wpdb->prefix . 'fleekdash_sessions';

        if ($wpdb->get_var("SHOW TABLES LIKE '$table_sessions'") == $table_sessions) {
            $total_sessions = $wpdb->get_var($wpdb->prepare("
                SELECT COUNT(*)
                FROM $table_sessions
                WHERE DATE(first_visit) BETWEEN %s AND %s
            ", $start->format('Y-m-d'), $end->format('Y-m-d')));

            // Use is_bounce column (already calculated)
            $bounced_sessions = $wpdb->get_var($wpdb->prepare("
                SELECT COUNT(*)
                FROM $table_sessions
                WHERE DATE(first_visit) BETWEEN %s AND %s
                AND is_bounce = 1
            ", $start->format('Y-m-d'), $end->format('Y-m-d')));

            if ($total_sessions > 0) {
                return round(($bounced_sessions / $total_sessions) * 100, 2);
            }
        }

        return 0;
    }

    /**
     * Get session duration for a period
     */
    public function getPeriodSessionDuration($start, $end)
    {
        global $wpdb;

        $table_sessions = $wpdb->prefix . 'fleekdash_sessions';

        if ($wpdb->get_var("SHOW TABLES LIKE '$table_sessions'") == $table_sessions) {
            // Use session_duration field (already calculated correctly)
            // TIMESTAMPDIFF between first_visit and last_visit can be inflated by persistent cookies
            $avg_duration = $wpdb->get_var($wpdb->prepare("
                SELECT AVG(session_duration)
                FROM $table_sessions
                WHERE DATE(first_visit) BETWEEN %s AND %s
                AND session_duration > 0
            ", $start->format('Y-m-d'), $end->format('Y-m-d')));

            if ($avg_duration > 0) {
                return round($avg_duration, 0);
            }
        }

        return 0;
    }

    /**
     * Get new users percentage for a period
     */
    public function getPeriodNewUsersPercentage($start, $end)
    {
        $total_users = count(get_users());
        if ($total_users == 0) {
            return 0;
        }

        $new_users = count(get_users([
            'date_query' => [
                [
                    'after' => $start->format('Y-m-d'),
                    'before' => $end->format('Y-m-d'),
                    'inclusive' => true
                ]
            ]
        ]));

        return round(($new_users / $total_users) * 100, 2);
    }

    /**
     * Get average posts per day
     */
    public function getAveragePostsPerDay($start, $end)
    {
        $days = $end->diff($start)->days + 1;
        if ($days == 0) {
            return 0;
        }

        $posts_count = count(\get_posts([
            'numberposts' => -1,
            'post_status' => 'publish',
            'fields' => 'ids',
            'date_query' => [
                [
                    'after' => $start->format('Y-m-d'),
                    'before' => $end->format('Y-m-d'),
                    'inclusive' => true
                ]
            ],
            'no_found_rows' => true,
            'update_post_meta_cache' => false,
            'update_post_term_cache' => false,
            'ignore_sticky_posts' => true,
            'cache_results' => false,
        ]));

        return round($posts_count / $days, 2);
    }
}
