<?php

namespace FleekDash\Controllers\SiteGrowth;

/**
 * Growth Data Processor
 *
 * Handles processing and formatting of growth meter data
 * Extracted from SiteGrowthMeterController for better organization
 *
 * @package FleekDash\Controllers\SiteGrowth
 * @since 2.2.0
 */
class GrowthDataProcessor
{
    /**
     * WordPress database object
     *
     * @var \wpdb
     */
    private $wpdb;

    /**
     * Tracking table name
     *
     * @var string
     */
    private $table_tracking;

    /**
     * Constructor
     */
    public function __construct()
    {
        global $wpdb;
        $this->wpdb = $wpdb;
        $this->table_tracking = $wpdb->prefix . 'fleekdash_tracking';
    }

    /**
     * Process events data (add points calculation)
     *
     * @param array $events Raw events from database
     * @return array Processed events with points_per_event
     */
    public function processEventsData($events)
    {
        if (empty($events) || !is_array($events)) {
            return [];
        }

        foreach ($events as &$event) {
            $event['points_per_event'] = $this->calculateEventPoints($event);
        }

        return $events;
    }

    /**
     * Calculate points for an event
     *
     * Now uses points_per_event column directly (Bug #1 & #2)
     * Maintains backward compatibility with tracking_config for old events
     *
     * @param array $event Event data
     * @return int Points per event
     */
    public function calculateEventPoints($event)
    {
        $default_points = 10;

        // Priority 1: Use points_per_event column (new way - after migration)
        if (isset($event['points_per_event']) && is_numeric($event['points_per_event'])) {
            return max(1, (int) $event['points_per_event']);
        }

        // Priority 2: Fallback to tracking_config (old way - backward compatibility)
        if (empty($event['tracking_config'])) {
            return $default_points;
        }

        // Handle double-encoded JSON
        $config = json_decode($event['tracking_config'], true);
        if (is_string($config)) {
            $config = json_decode($config, true);
        }

        // Handle both array and object cases
        if (is_array($config) && isset($config['points_override'])) {
            return max(1, (int) $config['points_override']);
        } elseif (is_object($config) && isset($config->points_override)) {
            return max(1, (int) $config->points_override);
        }

        // Also check for 'points' key (alternative naming)
        if (is_array($config) && isset($config['points'])) {
            return max(1, (int) $config['points']);
        } elseif (is_object($config) && isset($config->points)) {
            return max(1, (int) $config->points);
        }

        return $default_points;
    }

    /**
     * Process goals data
     *
     * @param array $goals Raw goals from database
     * @return array Processed goals with progress calculations
     */
    public function processGoalsData($goals)
    {
        if (empty($goals) || !is_array($goals)) {
            return [];
        }

        foreach ($goals as &$goal) {
            $goal = $this->calculateGoalProgress($goal);
        }

        return $goals;
    }

    /**
     * Calculate goal progress
     *
     * @param array $goal Goal data
     * @return array Goal with progress percentage
     */
    public function calculateGoalProgress($goal)
    {
        $current = (int) ($goal['current_value'] ?? 0);
        $target = (int) ($goal['target_value'] ?? 1);

        if ($target > 0) {
            $goal['progress_percentage'] = min(100, round(($current / $target) * 100, 2));
        } else {
            $goal['progress_percentage'] = 0;
        }

        return $goal;
    }

    /**
     * Calculate analytics data
     *
     * @param array $events All events
     * @param array $tracking_data Tracking records
     * @return array Analytics summary
     */
    public function calculateAnalytics($events, $tracking_data)
    {
        $total_points = 0;
        $total_events = 0;
        $events_by_type = [];

        foreach ($tracking_data as $record) {
            $total_points += (int) ($record['points_earned'] ?? 0);
            $total_events++;

            // Group by event type
            $event_id = (int) ($record['event_id'] ?? 0);
            $event = $this->findEventById($events, $event_id);

            if ($event) {
                $type = $event['event_type'] ?? 'unknown';
                if (!isset($events_by_type[$type])) {
                    $events_by_type[$type] = [
                        'type' => $type,
                        'count' => 0,
                        'points' => 0,
                    ];
                }

                $events_by_type[$type]['count']++;
                $events_by_type[$type]['points'] += (int) ($record['points_earned'] ?? 0);
            }
        }

        return [
            'total_points' => $total_points,
            'total_events' => $total_events,
            'average_points_per_event' => $total_events > 0 ? round($total_points / $total_events, 2) : 0,
            'events_by_type' => array_values($events_by_type),
        ];
    }

    /**
     * Find event by ID in events array
     *
     * @param array $events Events array
     * @param int $event_id Event ID to find
     * @return array|null Event data or null if not found
     */
    private function findEventById($events, $event_id)
    {
        foreach ($events as $event) {
            if ((int) ($event['id'] ?? 0) === $event_id) {
                return $event;
            }
        }

        return null;
    }

    /**
     * Build leaderboard data
     *
     * @param array $tracking_data Raw tracking data
     * @param int $limit Number of users to return
     * @return array Leaderboard array
     */
    public function buildLeaderboard($tracking_data, $limit = 10)
    {
        if (empty($tracking_data) || !is_array($tracking_data)) {
            return [];
        }

        // Group by user and calculate totals
        $user_points = [];

        foreach ($tracking_data as $record) {
            $user_id = (int) ($record['user_id'] ?? 0);
            $points = (int) ($record['points_earned'] ?? 0);

            if (!isset($user_points[$user_id])) {
                $user_points[$user_id] = [
                    'user_id' => $user_id,
                    'total_points' => 0,
                    'event_count' => 0,
                ];
            }

            $user_points[$user_id]['total_points'] += $points;
            $user_points[$user_id]['event_count']++;
        }

        // Sort by points descending
        usort($user_points, function ($a, $b) {
            return $b['total_points'] <=> $a['total_points'];
        });

        // Limit results
        $leaderboard = array_slice($user_points, 0, $limit);

        // Add user data
        foreach ($leaderboard as &$entry) {
            $user = \get_userdata($entry['user_id']);
            if ($user) {
                $entry['user_name'] = $user->display_name;
                $entry['user_email'] = $user->user_email;
                $entry['user_avatar'] = get_avatar_url($user->ID, ['size' => 48]);
            }
        }

        return $leaderboard;
    }

    /**
     * Get tracking data for analytics
     *
     * @param string $start_date Start date (Y-m-d)
     * @param string $end_date End date (Y-m-d)
     * @return array Tracking records
     */
    public function getTrackingData($start_date = null, $end_date = null)
    {
        $where_clauses = [];

        if ($start_date) {
            $where_clauses[] = $this->wpdb->prepare("tracked_at >= %s", $start_date);
        }

        if ($end_date) {
            $where_clauses[] = $this->wpdb->prepare("tracked_at <= %s", $end_date);
        }

        $where_sql = !empty($where_clauses) ? "WHERE " . implode(" AND ", $where_clauses) : "";
        $sql = "SELECT * FROM {$this->table_tracking} {$where_sql} ORDER BY tracked_at DESC";

        return $this->wpdb->get_results($sql, ARRAY_A);
    }
}
