/**
 * Exemplos de Uso do EventBus v2.0
 * 
 * Este arquivo demonstra os diferentes modos de uso do EventBus.
 * Não é incluído no build - apenas para documentação e referência.
 */

import { EventBus, EventBusConfig, EventPayloadMap } from './app/services';

// ============================================================================
// EXEMPLO 1: Uso Básico sem Tipos (JavaScript-like)
// ============================================================================

function example1_basicUsage() {
    console.log('=== Exemplo 1: Uso Básico ===');
    
    // Obter instância singleton sem configuração
    const bus = EventBus.getInstance();
    
    // Inscrever em um evento
    const unsubscribe = bus.subscribe('userLogin', (userData) => {
        console.log('Usuário fez login:', userData);
    });
    
    // Publicar evento
    bus.publish('userLogin', { userId: '123', name: 'João' });
    
    // Desinscrever
    unsubscribe();
}

// ============================================================================
// EXEMPLO 2: Uso com Tipos de Eventos (TypeScript Simples)
// ============================================================================

function example2_withEventTypes() {
    console.log('=== Exemplo 2: Com Tipos de Eventos ===');
    
    // Definir tipos de eventos como união de strings literais
    type AppEvents = 'userLogin' | 'userLogout' | 'dataLoaded' | 'error';
    
    // Criar instância tipada
    const bus = EventBus.getInstance<AppEvents>();
    
    // TypeScript agora valida os nomes de eventos
    bus.subscribe('userLogin', (data) => {
        console.log('Login:', data);
    });
    
    // bus.subscribe('eventoInvalido', ...); // ❌ Erro de compilação
    
    bus.publish('userLogin', { userId: '456' });
    bus.publish('dataLoaded', { records: 10 });
}

// ============================================================================
// EXEMPLO 3: Uso Avançado com Payloads Tipados
// ============================================================================

function example3_withTypedPayloads() {
    console.log('=== Exemplo 3: Payloads Tipados ===');
    
    // Definir tipos de eventos
    type AppEvents = 'login' | 'logout' | 'error';
    
    // Definir tipos dos payloads para cada evento
    interface AppEventPayloads extends EventPayloadMap<AppEvents> {
        login: {
            userId: string;
            username: string;
            timestamp: Date;
        };
        logout: {
            userId: string;
            reason: 'manual' | 'timeout' | 'error';
        };
        error: {
            code: number;
            message: string;
            stack?: string;
        };
    }
    
    // Criar instância com tipos avançados
    const bus = EventBus.create<AppEvents, AppEventPayloads>();
    
    // Callbacks agora têm payloads totalmente tipados!
    bus.subscribe('login', (payload) => {
        // payload é tipado como { userId: string; username: string; timestamp: Date }
        console.log(`${payload.username} fez login em ${payload.timestamp}`);
        console.log('User ID:', payload.userId);
    });
    
    bus.subscribe('logout', (payload) => {
        // payload é tipado como { userId: string; reason: 'manual' | 'timeout' | 'error' }
        console.log(`Logout reason: ${payload.reason}`);
    });
    
    bus.subscribe('error', (payload) => {
        // payload é tipado como { code: number; message: string; stack?: string }
        console.error(`Erro ${payload.code}: ${payload.message}`);
    });
    
    // Publicar eventos com validação de tipos
    bus.publish('login', {
        userId: '789',
        username: 'maria',
        timestamp: new Date()
    });
    
    bus.publish('logout', {
        userId: '789',
        reason: 'manual'
    });
    
    // bus.publish('login', { invalid: 'data' }); // ❌ Erro de compilação
}

// ============================================================================
// EXEMPLO 4: Configuração com Validação de Eventos
// ============================================================================

function example4_withValidation() {
    console.log('=== Exemplo 4: Validação de Eventos ===');
    
    type AppEvents = 'login' | 'logout' | 'refresh';
    
    const config: EventBusConfig<AppEvents> = {
        allowedEvents: ['login', 'logout'], // apenas estes eventos são permitidos
        validateEvents: true, // ativa validação em runtime
    };
    
    const bus = EventBus.create<AppEvents>(config);
    
    // OK - eventos permitidos
    bus.subscribe('login', (data) => console.log('Login:', data));
    bus.publish('login', { userId: '123' });
    
    try {
        // ❌ Erro em runtime - 'refresh' não está em allowedEvents
        bus.publish('refresh', {});
    } catch (error) {
        console.error('Erro capturado:', (error as Error).message);
    }
}

// ============================================================================
// EXEMPLO 5: Error Handling Customizado
// ============================================================================

function example5_customErrorHandling() {
    console.log('=== Exemplo 5: Error Handling Customizado ===');
    
    const errorLog: Array<{ event: string; error: Error }> = [];
    
    const config: EventBusConfig<string> = {
        onError: (error, eventName) => {
            console.error(`[CustomErrorHandler] Erro no evento "${eventName}":`, error.message);
            errorLog.push({ event: eventName, error });
        },
    };
    
    const bus = EventBus.create(config);
    
    // Callback que lança erro
    bus.subscribe('processData', (data) => {
        throw new Error('Falha no processamento');
    });
    
    // Callback normal
    bus.subscribe('processData', (data) => {
        console.log('Outro callback executou normalmente');
    });
    
    // Publicar - primeiro callback falha, segundo executa
    bus.publish('processData', { value: 42 });
    
    console.log('Erros capturados:', errorLog.length);
}

// ============================================================================
// EXEMPLO 6: Logger Customizado
// ============================================================================

function example6_customLogger() {
    console.log('=== Exemplo 6: Logger Customizado ===');
    
    const customLogger = {
        error: (message: string, ...args: any[]) => {
            console.log('[CUSTOM ERROR]', message, ...args);
        },
        warn: (message: string, ...args: any[]) => {
            console.log('[CUSTOM WARN]', message, ...args);
        },
    };
    
    const config: EventBusConfig<string> = {
        logger: customLogger,
    };
    
    const bus = EventBus.create(config);
    
    bus.subscribe('test', () => {
        throw new Error('Teste de erro');
    });
    
    bus.publish('test'); // Usa logger customizado
}

// ============================================================================
// EXEMPLO 7: Métricas de Uso
// ============================================================================

function example7_metrics() {
    console.log('=== Exemplo 7: Métricas ===');
    
    const config: EventBusConfig<string> = {
        enableMetrics: true, // ativa coleta de métricas
    };
    
    const bus = EventBus.create(config);
    
    // Criar subscriptions
    bus.subscribe('event1', () => console.log('Event 1 - Handler 1'));
    bus.subscribe('event1', () => console.log('Event 1 - Handler 2'));
    bus.subscribe('event2', () => console.log('Event 2'));
    
    // Publicar eventos
    bus.publish('event1', 'data1');
    bus.publish('event1', 'data2');
    bus.publish('event2', 'data3');
    
    // Consultar métricas
    const metrics = bus.getMetrics();
    if (metrics) {
        console.log('Total de subscriptions:', metrics.totalSubscriptions);
        console.log('Total de publishes:', metrics.totalPublishes);
        console.log('Total de erros:', metrics.totalErrors);
        console.log('Último publish:', new Date(metrics.lastPublishTimestamp!));
        console.log('\nMétricas por evento:');
        Object.entries(metrics.byEvent).forEach(([event, stats]) => {
            console.log(`  ${event}:`);
            console.log(`    - Subscribers: ${stats.subscriptionCount}`);
            console.log(`    - Publishes: ${stats.publishCount}`);
        });
    }
}

// ============================================================================
// EXEMPLO 8: Singleton vs Instâncias Independentes
// ============================================================================

function example8_singletonVsCreate() {
    console.log('=== Exemplo 8: Singleton vs Create ===');
    
    // Singleton - sempre retorna a mesma instância
    const singleton1 = EventBus.getInstance();
    const singleton2 = EventBus.getInstance();
    console.log('Singletons são iguais?', singleton1 === singleton2); // true
    
    // Create - sempre cria nova instância
    const instance1 = EventBus.create();
    const instance2 = EventBus.create();
    console.log('Instâncias create são iguais?', instance1 === instance2); // false
    
    // Uso prático: modules isolados
    const authBus = EventBus.create<'login' | 'logout'>();
    const dataBus = EventBus.create<'load' | 'save'>();
    
    authBus.subscribe('login', () => console.log('Auth: Login'));
    dataBus.subscribe('load', () => console.log('Data: Load'));
    
    // Eventos não interferem entre instâncias
    authBus.publish('login');
    dataBus.publish('load');
}

// ============================================================================
// EXEMPLO 9: Inspeção do EventBus
// ============================================================================

function example9_inspection() {
    console.log('=== Exemplo 9: Inspeção ===');
    
    const bus = EventBus.create<'event1' | 'event2' | 'event3'>();
    
    // Adicionar subscribers
    bus.subscribe('event1', () => {});
    bus.subscribe('event1', () => {});
    bus.subscribe('event2', () => {});
    
    // Listar eventos ativos
    const activeEvents = bus.getEventNames();
    console.log('Eventos ativos:', activeEvents); // ['event1', 'event2']
    
    // Verificar se evento tem subscribers
    console.log('event1 tem subscribers?', bus.hasSubscribers('event1')); // true
    console.log('event3 tem subscribers?', bus.hasSubscribers('event3')); // false
    
    // Contar subscribers
    console.log('Subscribers de event1:', bus.getSubscriberCount('event1')); // 2
    console.log('Subscribers de event2:', bus.getSubscriberCount('event2')); // 1
    console.log('Subscribers de event3:', bus.getSubscriberCount('event3')); // 0
    
    // Obter configuração
    const config = bus.getConfig();
    console.log('Configuração:', config);
}

// ============================================================================
// EXEMPLO 10: Uso em Testes
// ============================================================================

function example10_testing() {
    console.log('=== Exemplo 10: Uso em Testes ===');
    
    // ANTES de cada teste - criar instância isolada
    const bus = EventBus.create<'testEvent'>();
    
    // Seu teste
    let callCount = 0;
    bus.subscribe('testEvent', () => {
        callCount++;
    });
    
    bus.publish('testEvent');
    bus.publish('testEvent');
    
    console.log('Callback foi chamado:', callCount, 'vezes'); // 2
    
    // DEPOIS do teste - limpar (se usar singleton)
    // EventBus.resetInstance(); // ⚠️ apenas em testes!
    
    // OU limpar eventos manualmente
    bus.clearAllEvents();
    console.log('Eventos após clear:', bus.getEventNames()); // []
}

// ============================================================================
// EXEMPLO 11: Pattern de Unsubscribe
// ============================================================================

function example11_unsubscribePatterns() {
    console.log('=== Exemplo 11: Patterns de Unsubscribe ===');
    
    const bus = EventBus.create<'data'>();
    
    // Pattern 1: Usar return de subscribe()
    const unsubscribe1 = bus.subscribe('data', () => console.log('Handler 1'));
    unsubscribe1(); // desinscreve
    
    // Pattern 2: Guardar referência do callback
    const handler2 = () => console.log('Handler 2');
    bus.subscribe('data', handler2);
    bus.unsubscribe('data', handler2); // desinscreve
    
    // Pattern 3: Limpar evento inteiro
    bus.subscribe('data', () => console.log('Handler 3'));
    bus.subscribe('data', () => console.log('Handler 4'));
    bus.clearEvent('data'); // remove todos os subscribers de 'data'
    
    // Pattern 4: Limpar tudo
    bus.subscribe('data', () => console.log('Handler 5'));
    bus.clearAllEvents(); // remove todos os eventos
}

// ============================================================================
// EXEMPLO 12: Integração com CDN
// ============================================================================

/*
// Para usar via CDN em HTML:

<!DOCTYPE html>
<html>
<head>
  <script src="https://cdn.example.com/jsegd/jsegd.js"></script>
</head>
<body>
  <script>
    // Acessar EventBus do namespace global (se configurado)
    const { EventBus } = window.jsegd;
    
    // Usar normalmente
    const bus = EventBus.getInstance();
    
    bus.subscribe('pageLoad', (data) => {
      console.log('Página carregou:', data);
    });
    
    bus.publish('pageLoad', { url: window.location.href });
  </script>
</body>
</html>
*/

// ============================================================================
// Executar exemplos
// ============================================================================

if (require.main === module) {
    example1_basicUsage();
    example2_withEventTypes();
    example3_withTypedPayloads();
    example4_withValidation();
    example5_customErrorHandling();
    example6_customLogger();
    example7_metrics();
    example8_singletonVsCreate();
    example9_inspection();
    example10_testing();
    example11_unsubscribePatterns();
}
