import Echo from 'laravel-echo';
import Pusher from 'pusher-js';

declare global {
  interface Window { EchoInstance?: any; }
}

type InitOptions = {
  authEndpoint?: string;
  key?: string;
  wsHost?: string;
  wsPort?: number;
  forceTLS?: boolean;
};

const defaultCsrf = () => (document.querySelector('meta[name="csrf-token"]') as HTMLMetaElement)?.content || '';

export function isEchoInitialized(): boolean {
  return !!window.EchoInstance;
}

export function initEchoOnce(opts: InitOptions = {}) {
  if (window.EchoInstance) return window.EchoInstance;

  const getEnv = (name: string, fallback?: any) => {
    // Prefer values exposed on window (build-time injection), then process.env if available
    const w = (window as any)[name];
    if (w !== undefined) return w;
    if (typeof process !== 'undefined' && process && (process as any).env && (process as any).env[name] !== undefined) {
      return (process as any).env[name];
    }
    return fallback;
  };

  const getMeta = (name: string) => (document.querySelector(`meta[name="${name}"]`) as HTMLMetaElement)?.content;

  const authEndpoint = opts.authEndpoint || getEnv('MIX_BROADCAST_AUTH', '/broadcasting/auth') || getMeta('broadcast-auth');
  const key = opts.key || getEnv('MIX_PUSHER_APP_KEY') || getMeta('pusher-key') || 'app-key';
  const cluster = getEnv('MIX_PUSHER_APP_CLUSTER') || getMeta('pusher-cluster') || undefined;
  const wsHost = opts.wsHost || getEnv('MIX_PUSHER_HOST') || window.location.hostname;
  const wsPort = opts.wsPort ?? Number(getEnv('MIX_PUSHER_PORT', getMeta('pusher-port') || 6001));
  const forceTLS = opts.forceTLS ?? (getEnv('MIX_PUSHER_SCHEME') === 'https' || getMeta('pusher-force-tls') === 'true' || false);

  // Ensure pusher-js is available on window if needed by Echo
  (window as any).Pusher = Pusher;

  const echoOptions: any = {
    broadcaster: 'pusher',
    key,
    wsHost,
    wsPort,
    forceTLS,
    disableStats: true,
    auth: {
      endpoint: authEndpoint,
      headers: {
        'X-Requested-With': 'XMLHttpRequest',
        'X-CSRF-TOKEN': defaultCsrf(),
      }
    }
  };

  if (cluster) echoOptions.cluster = cluster;

  const echo = new Echo(echoOptions as any);

  window.EchoInstance = echo;

  // Optional: log connection state for diagnostics
  try {
    if ((echo.connector as any)?.pusher) {
      (echo.connector as any).pusher.connection.bind('connected', () => console.debug('Echo connected'));
      (echo.connector as any).pusher.connection.bind('disconnected', () => console.debug('Echo disconnected'));
      (echo.connector as any).pusher.connection.bind('error', (err: any) => console.warn('Echo error', err));
    }
  } catch (e) {
    console.debug('Echo diagnostics setup failed', e);
  }

  return echo;
}

const subscribers = new Map<string, any>();

export function subscribeOnce(channelName: string, event: string, handler: (payload: any) => void) {
  const key = `${channelName}:${event}`;
  if (subscribers.has(key)) return;
  const echo = initEchoOnce();
  echo.private(channelName).listen(event, handler);
  subscribers.set(key, handler);
}

export function unsubscribe(channelName: string, event: string) {
  const key = `${channelName}:${event}`;
  if (!subscribers.has(key)) return;
  const echo = window.EchoInstance as any;
  if (echo) {
    try { echo.private(channelName).stopListening(event); } catch (e) { /* ignore */ }
  }
  subscribers.delete(key);
}

export default {
  initEchoOnce,
  isEchoInitialized,
  subscribeOnce,
  unsubscribe,
};
