import { Injectable } from '@angular/core';
import { Observable } from 'rxjs';
import { GameStreamEvent, ErrorEvent } from '../models/game.models';

const WS_CONNECT_TIMEOUT_MS = 3000;

@Injectable({ providedIn: 'root' })
export class StreamHandlerService {
  createGameStream(wsUrl: string, gameId: string, token: string): Observable<GameStreamEvent> {
    return new Observable<GameStreamEvent>((observer) => {
      const ws = new WebSocket(wsUrl);
      let connected = false;

      const emitErrorEvent = (message: string): void => {
        const errorEvent: ErrorEvent = {
          type: 'error',
          error: { code: 'STREAM_ERROR', message },
        };
        observer.next(errorEvent);
      };

      const failAndComplete = (reason: string): void => {
        console.warn(`[StreamHandler] WebSocket failed for ${gameId}: ${reason}`);
        emitErrorEvent(reason);
        observer.complete();
      };

      const connectionTimeoutId = setTimeout(() => {
        if (!connected) {
          ws.close();
          failAndComplete('WebSocket connection timed out — falling back to polling');
        }
      }, WS_CONNECT_TIMEOUT_MS);

      ws.onopen = () => {
        connected = true;
        clearTimeout(connectionTimeoutId);
        console.log(`[StreamHandler] WebSocket connected for ${gameId}`);
        ws.send(JSON.stringify({ type: 'auth', token }));
      };

      ws.onmessage = (message) => {
        const payload = typeof message.data === 'string' ? message.data : '';
        if (!payload.trim()) return;
        try {
          const event = JSON.parse(payload) as GameStreamEvent;
          observer.next(event);
        } catch {
          // ignore malformed frames
        }
      };

      ws.onerror = () => {
        clearTimeout(connectionTimeoutId);
        if (!connected) {
          failAndComplete('WebSocket connection error — falling back to polling');
        }
      };

      ws.onclose = () => {
        clearTimeout(connectionTimeoutId);
        if (connected) {
          observer.complete();
        }
      };

      return () => {
        ws.close();
      };
    });
  }
}
