<?php

namespace App\Services\Analytics;

use App\Models\User;
use App\Models\AnalyticsEvent;
use App\Models\UserSession;
use App\DTOs\TelegramMessage;
use App\DTOs\TelegramCallback;
use App\Services\Core\ConfigurationManager;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\Log;
use Carbon\Carbon;

class AnalyticsService
{
    private ConfigurationManager $config;

    public function __construct(ConfigurationManager $config)
    {
        $this->config = $config;
    }

    /**
     * Track a message event
     */
    public function trackMessage(User $user, TelegramMessage $message): void
    {
        $eventData = [
            'text' => $this->sanitizeText($message->text),
            'chat_id' => $message->chatId,
            'message_type' => $this->getMessageType($message->text),
            'is_command' => $message->isCommand(),
        ];

        if ($message->isCommand()) {
            $eventData['command'] = $message->getCommand();
            $eventData['command_args'] = $message->getCommandArgs();
        }

        $this->trackEvent($user, 'message', $eventData);
    }

    /**
     * Track a callback event
     */
    public function trackCallback(User $user, TelegramCallback $callback): void
    {
        $eventData = [
            'callback_data' => $callback->data,
            'chat_id' => $callback->chatId,
            'action' => $callback->getAction(),
            'payload' => $callback->getPayload(),
            'prefix' => $callback->getPrefix(),
        ];

        $this->trackEvent($user, 'callback', $eventData);
    }

    /**
     * Track a generic event
     */
    public function trackEvent(User $user, string $eventType, array $data = []): void
    {
        try {
            if ($this->config->get('modules.analytics.anonymize_data', false)) {
                $data = $this->anonymizeData($data);
            }

            AnalyticsEvent::create([
                'user_id' => $user->id,
                'event_type' => $eventType,
                'event_data' => $data,
                'ip_address' => request()->ip(),
                'user_agent' => request()->userAgent(),
                'created_at' => now(),
            ]);

        } catch (\Throwable $e) {
            Log::error('Failed to track analytics event', [
                'user_id' => $user->id,
                'event_type' => $eventType,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Track user session
     */
    public function trackSession(User $user): void
    {
        try {
            $sessionTimeout = 30; // 30 minutes
            $lastActivity = $user->last_activity_at ?? now()->subHours(1);

            // Check if we need to start a new session
            if ($lastActivity->addMinutes($sessionTimeout)->isPast()) {
                UserSession::create([
                    'user_id' => $user->id,
                    'session_start' => now(),
                    'ip_address' => request()->ip(),
                    'user_agent' => request()->userAgent(),
                ]);
            } else {
                // Update existing session
                $session = UserSession::where('user_id', $user->id)
                    ->whereNull('session_end')
                    ->latest()
                    ->first();

                if ($session) {
                    $session->touch(); // Update updated_at timestamp
                }
            }

        } catch (\Throwable $e) {
            Log::error('Failed to track user session', [
                'user_id' => $user->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Update user activity timestamp
     */
    public function updateUserActivity(User $user): void
    {
        try {
            $user->update(['last_activity_at' => now()]);
        } catch (\Throwable $e) {
            Log::error('Failed to update user activity', [
                'user_id' => $user->id,
                'error' => $e->getMessage(),
            ]);
        }
    }

    /**
     * Get dashboard statistics
     */
    public function getDashboardStats(): array
    {
        return Cache::remember('analytics_dashboard_stats', 300, function () {
            $now = now();
            
            return [
                'total_users' => User::count(),
                'active_today' => User::whereDate('last_activity_at', $now->toDateString())->count(),
                'active_week' => User::where('last_activity_at', '>=', $now->subDays(7))->count(),
                'messages_today' => AnalyticsEvent::where('event_type', 'message')
                    ->whereDate('created_at', $now->toDateString())->count(),
                'messages_week' => AnalyticsEvent::where('event_type', 'message')
                    ->where('created_at', '>=', $now->subDays(7))->count(),
                'callbacks_today' => AnalyticsEvent::where('event_type', 'callback')
                    ->whereDate('created_at', $now->toDateString())->count(),
                'callbacks_week' => AnalyticsEvent::where('event_type', 'callback')
                    ->where('created_at', '>=', $now->subDays(7))->count(),
            ];
        });
    }

    /**
     * Get user statistics
     */
    public function getUserStats(): array
    {
        return Cache::remember('analytics_user_stats', 300, function () {
            $now = now();
            
            $stats = [
                'total_users' => User::count(),
                'new_users_today' => User::whereDate('created_at', $now->toDateString())->count(),
                'new_users_week' => User::where('created_at', '>=', $now->subDays(7))->count(),
                'active_today' => User::whereDate('last_activity_at', $now->toDateString())->count(),
                'active_week' => User::where('last_activity_at', '>=', $now->subDays(7))->count(),
                'active_month' => User::where('last_activity_at', '>=', $now->subDays(30))->count(),
            ];

            // Get top active users
            $stats['top_users'] = AnalyticsEvent::select('user_id', DB::raw('count(*) as activity_count'))
                ->where('created_at', '>=', $now->subDays(7))
                ->groupBy('user_id')
                ->orderBy('activity_count', 'desc')
                ->limit(10)
                ->get()
                ->toArray();

            return $stats;
        });
    }

    /**
     * Get content statistics
     */
    public function getContentStats(): array
    {
        return Cache::remember('analytics_content_stats', 300, function () {
            $now = now();
            
            $stats = [];

            // Popular commands
            $stats['popular_commands'] = AnalyticsEvent::select(
                    DB::raw("JSON_UNQUOTE(JSON_EXTRACT(event_data, '$.command')) as command"),
                    DB::raw('count(*) as count')
                )
                ->where('event_type', 'message')
                ->whereRaw("JSON_EXTRACT(event_data, '$.is_command') = true")
                ->where('created_at', '>=', $now->subDays(7))
                ->groupBy('command')
                ->orderBy('count', 'desc')
                ->limit(10)
                ->get()
                ->toArray();

            // Popular callbacks
            $stats['popular_callbacks'] = AnalyticsEvent::select(
                    DB::raw("JSON_UNQUOTE(JSON_EXTRACT(event_data, '$.callback_data')) as callback"),
                    DB::raw('count(*) as count')
                )
                ->where('event_type', 'callback')
                ->where('created_at', '>=', $now->subDays(7))
                ->groupBy('callback')
                ->orderBy('count', 'desc')
                ->limit(10)
                ->get()
                ->toArray();

            return $stats;
        });
    }

    /**
     * Get event statistics
     */
    public function getEventStats(): array
    {
        return Cache::remember('analytics_event_stats', 300, function () {
            $now = now();
            
            $stats = [
                'total_events' => AnalyticsEvent::count(),
                'events_today' => AnalyticsEvent::whereDate('created_at', $now->toDateString())->count(),
                'events_week' => AnalyticsEvent::where('created_at', '>=', $now->subDays(7))->count(),
            ];

            // Top events by type
            $stats['top_events'] = AnalyticsEvent::select('event_type as type', DB::raw('count(*) as count'))
                ->where('created_at', '>=', $now->subDays(7))
                ->groupBy('event_type')
                ->orderBy('count', 'desc')
                ->limit(10)
                ->get()
                ->toArray();

            return $stats;
        });
    }

    /**
     * Get user behavior patterns
     */
    public function getUserBehaviorPatterns(User $user, int $days = 30): array
    {
        $events = AnalyticsEvent::where('user_id', $user->id)
            ->where('created_at', '>=', now()->subDays($days))
            ->orderBy('created_at')
            ->get();

        $patterns = [
            'total_events' => $events->count(),
            'daily_activity' => [],
            'hourly_activity' => [],
            'favorite_commands' => [],
            'session_patterns' => [],
        ];

        // Daily activity distribution
        $dailyGroups = $events->groupBy(function ($event) {
            return $event->created_at->format('Y-m-d');
        });

        foreach ($dailyGroups as $date => $dayEvents) {
            $patterns['daily_activity'][$date] = $dayEvents->count();
        }

        // Hourly activity distribution
        $hourlyGroups = $events->groupBy(function ($event) {
            return $event->created_at->format('H');
        });

        foreach ($hourlyGroups as $hour => $hourEvents) {
            $patterns['hourly_activity'][$hour] = $hourEvents->count();
        }

        // Favorite commands
        $commandEvents = $events->where('event_type', 'message')
            ->filter(function ($event) {
                return isset($event->event_data['is_command']) && $event->event_data['is_command'];
            });

        $commandCounts = $commandEvents->groupBy('event_data.command')
            ->map->count()
            ->sortDesc();

        $patterns['favorite_commands'] = $commandCounts->take(10)->toArray();

        return $patterns;
    }

    /**
     * Clean up old analytics data
     */
    public function cleanupOldData(): int
    {
        $retentionDays = $this->config->get('modules.analytics.retention_days', 90);
        $cutoffDate = now()->subDays($retentionDays);

        try {
            $deletedEvents = AnalyticsEvent::where('created_at', '<', $cutoffDate)->delete();
            $deletedSessions = UserSession::where('created_at', '<', $cutoffDate)->delete();

            Log::info('Analytics cleanup completed', [
                'deleted_events' => $deletedEvents,
                'deleted_sessions' => $deletedSessions,
                'retention_days' => $retentionDays,
            ]);

            return $deletedEvents + $deletedSessions;

        } catch (\Throwable $e) {
            Log::error('Analytics cleanup failed', [
                'error' => $e->getMessage(),
            ]);
            return 0;
        }
    }

    /**
     * Initialize analytics system
     */
    public function initialize(): void
    {
        // Clear any cached statistics
        $this->clearCache();
        
        Log::info('Analytics service initialized');
    }

    /**
     * Clear analytics cache
     */
    public function clearCache(): void
    {
        Cache::forget('analytics_dashboard_stats');
        Cache::forget('analytics_user_stats');
        Cache::forget('analytics_content_stats');
        Cache::forget('analytics_event_stats');
    }

    /**
     * Sanitize text for storage
     */
    private function sanitizeText(?string $text): ?string
    {
        if (!$text) {
            return null;
        }

        // Limit text length for storage
        $maxLength = 500;
        if (strlen($text) > $maxLength) {
            $text = substr($text, 0, $maxLength) . '...';
        }

        return $text;
    }

    /**
     * Determine message type
     */
    private function getMessageType(string $text): string
    {
        if (str_starts_with($text, '/')) {
            return 'command';
        }
        
        if (filter_var($text, FILTER_VALIDATE_URL)) {
            return 'url';
        }
        
        if (is_numeric($text)) {
            return 'number';
        }
        
        if (strlen($text) > 100) {
            return 'long_text';
        }
        
        return 'text';
    }

    /**
     * Anonymize sensitive data
     */
    private function anonymizeData(array $data): array
    {
        $sensitiveFields = ['text', 'user_agent', 'ip_address'];
        
        foreach ($sensitiveFields as $field) {
            if (isset($data[$field])) {
                $data[$field] = hash('sha256', $data[$field]);
            }
        }
        
        return $data;
    }
}