<?php

namespace App\Services\Analytics;

use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Contracts\Events\Dispatcher;

class EventBus
{
    private static array $listeners = [];
    private static ?Dispatcher $eventDispatcher = null;
    /**
     * Track user analytics events
     */
    public static function track(int|string $telegramUserId, string $type, array $props = []): void
    {
        // Find or create user by telegram ID
        $telegramId = (string) $telegramUserId;
        $user = DB::table('users')->where('tg_id', $telegramId)->first();

        if (!$user) {
            // Create user if doesn't exist
            $userId = DB::table('users')->insertGetId([
                'tg_id' => $telegramId,
                'role' => 'user',
                'created_at' => now(),
                'updated_at' => now(),
            ]);
        } else {
            $userId = $user->id;
        }

        // Insert event
        try {
            DB::table('events')->insert([
                'user_id' => $userId,
                'type' => $type,
                'payload_json' => json_encode($props),
                'created_at' => now(),
                'updated_at' => now(),
            ]);
        } catch (\Throwable $e) {
            // Log error but don't throw to avoid breaking the main flow
            Log::warning('EventBus track failed', [
                'telegram_user_id' => $telegramUserId,
                'type' => $type,
                'error' => $e->getMessage()
            ]);
        }
    }

    /**
     * Emit an event to all registered listeners
     */
    public static function emit(string $event, array $data = []): void
    {
        // Use Laravel's event dispatcher if available
        if (self::$eventDispatcher) {
            self::$eventDispatcher->dispatch($event, $data);
        }

        // Also trigger our custom listeners
        if (isset(self::$listeners[$event])) {
            foreach (self::$listeners[$event] as $listener) {
                try {
                    $listener($data);
                } catch (\Throwable $e) {
                    Log::error('EventBus listener failed', [
                        'event' => $event,
                        'listener' => is_callable($listener) ? 'callable' : get_class($listener),
                        'error' => $e->getMessage()
                    ]);
                }
            }
        
            /**
             * Emit module-specific events with namespace
             */
            public static function emitModuleEvent(string $module, string $event, array $data = []): void
            {
                $namespacedEvent = "module.{$module}.{$event}";
                self::emit($namespacedEvent, array_merge($data, ['module' => $module]));
            }
        
            /**
             * Listen to module-specific events
             */
            public static function listenToModule(string $module, string $event, callable $listener): void
            {
                $namespacedEvent = "module.{$module}.{$event}";
                self::listen($namespacedEvent, $listener);
            }
        
            /**
             * Emit user-related events
             */
            public static function emitUserEvent(int $userId, string $event, array $data = []): void
            {
                $userEvent = "user.{$event}";
                self::emit($userEvent, array_merge($data, ['user_id' => $userId]));
            }
        
            /**
             * Listen to user-related events
             */
            public static function listenToUser(string $event, callable $listener): void
            {
                $userEvent = "user.{$event}";
                self::listen($userEvent, $listener);
            }
        }

        Log::debug('Event emitted', ['event' => $event, 'data_keys' => array_keys($data)]);
    }

    /**
     * Register an event listener
     */
    public static function listen(string $event, callable $listener): void
    {
        if (!isset(self::$listeners[$event])) {
            self::$listeners[$event] = [];
        }

        self::$listeners[$event][] = $listener;
        Log::debug('Event listener registered', ['event' => $event]);
    }

    /**
     * Remove event listeners for a specific event
     */
    public static function forget(string $event): void
    {
        unset(self::$listeners[$event]);
        Log::debug('Event listeners removed', ['event' => $event]);
    }

    /**
     * Get all registered listeners for debugging
     */
    public static function getListeners(): array
    {
        return array_map(fn($listeners) => count($listeners), self::$listeners);
    }

    /**
     * Set the Laravel event dispatcher
     */
    public static function setEventDispatcher(Dispatcher $dispatcher): void
    {
        self::$eventDispatcher = $dispatcher;
    }

    /**
     * Clear all listeners (useful for testing)
     */
    public static function clearListeners(): void
    {
        self::$listeners = [];
    }
}

