/**
 * TransportProbe - Test endpoint availability
 */

import type { RootEndpoint } from './root_registry';
/** @deprecated Use RootEndpoint */
type RealmEndpoint = RootEndpoint;

export interface ProbeResult {
  available: boolean;
  latencyMs?: number;
  error?: string;
}

export interface ProbeCache {
  result: ProbeResult;
  expires: number;
}

export class TransportProbe {
  private _cache: Map<string, ProbeCache> = new Map();
  private _positiveTtlMs = 30000; // 30s for available
  private _negativeTtlMs = 5000;  // 5s for unavailable

  /**
   * Probe an endpoint for availability.
   * Returns cached result if valid.
   */
  async probe(endpoint: RootEndpoint, timeoutMs = 2000): Promise<ProbeResult> {
    const key = `${endpoint.type}:${endpoint.url}`;

    // Check cache
    const cached = this._cache.get(key);
    if (cached && cached.expires > Date.now()) {
      return cached.result;
    }

    // Memory transport is always available
    if (endpoint.type === 'memory') {
      return this._cacheResult(key, { available: true, latencyMs: 0 }, true);
    }

    // Probe external endpoint
    const start = Date.now();
    try {
      const available = await this._probeEndpoint(endpoint, timeoutMs);
      const latencyMs = Date.now() - start;
      return this._cacheResult(key, { available, latencyMs }, available);
    } catch (err) {
      return this._cacheResult(
        key,
        { available: false, error: String(err) },
        false
      );
    }
  }

  /**
   * Clear probe cache for an endpoint or all endpoints.
   */
  clearCache(endpoint?: RootEndpoint): void {
    if (endpoint) {
      const key = `${endpoint.type}:${endpoint.url}`;
      this._cache.delete(key);
    } else {
      this._cache.clear();
    }
  }

  private async _probeEndpoint(
    endpoint: RootEndpoint,
    timeoutMs: number
  ): Promise<boolean> {
    // Implementation depends on endpoint type
    if (endpoint.type === 'ws' || endpoint.type === 'wss') {
      return this._probeWebSocket(endpoint.url, timeoutMs);
    }

    return false;
  }

  private _probeWebSocket(url: string, timeoutMs: number): Promise<boolean> {
    // Node.js doesn't have WebSocket, return false
    if (typeof WebSocket === 'undefined') {
      return Promise.resolve(false);
    }

    return new Promise((resolve) => {
      const ws = new WebSocket(url);
      const timer = setTimeout(() => {
        ws.close();
        resolve(false);
      }, timeoutMs);

      ws.onopen = () => {
        clearTimeout(timer);
        ws.close();
        resolve(true);
      };

      ws.onerror = () => {
        clearTimeout(timer);
        ws.close();
        resolve(false);
      };
    });
  }

  private _cacheResult(
    key: string,
    result: ProbeResult,
    positive: boolean
  ): ProbeResult {
    const ttl = positive ? this._positiveTtlMs : this._negativeTtlMs;
    this._cache.set(key, { result, expires: Date.now() + ttl });
    return result;
  }
}
