/**
 * Agent HTTP client — SSE events + POST commands (replaces WebSocket).
 */

export class AgentHttpClient extends EventTarget {
  constructor() {
    super();
    this.eventSource = null;
    this.reconnectAttempts = 0;
    this.maxReconnectDelay = 10000;
    this.reconnectDelay = 1000;
    this.isIntentionallyClosed = false;
    this.reconnectTimer = null;
    this.connectionState = 'idle';
  }

  connect() {
    if (this.connectionState === 'connecting') return;
    if (this.eventSource && this.eventSource.readyState === EventSource.OPEN) return;

    this.isIntentionallyClosed = false;
    this.connectionState = 'connecting';
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
    }
    if (this.eventSource) {
      this.eventSource.close();
      this.eventSource = null;
    }

    this.eventSource = new EventSource('/api/events');

    this.eventSource.onopen = () => {
      console.log('[HTTP] Connected (SSE)');
      this.reconnectAttempts = 0;
      this.connectionState = 'open';
      this.dispatchEvent(new CustomEvent('connected'));
    };

    this.eventSource.onmessage = (event) => {
      try {
        const message = JSON.parse(event.data);
        this.handleMessage(message);
      } catch (error) {
        console.error('[HTTP] Failed to parse SSE message:', error);
      }
    };

    this.eventSource.onerror = () => {
      console.error('[HTTP] SSE error');
      this.connectionState = 'closed';
      this.dispatchEvent(new CustomEvent('error'));
      if (this.eventSource) {
        this.eventSource.close();
        this.eventSource = null;
      }
      this.dispatchEvent(new CustomEvent('disconnected'));
      if (!this.isIntentionallyClosed) {
        this.attemptReconnect();
      }
    };
  }

  disconnect() {
    this.isIntentionallyClosed = true;
    this.connectionState = 'closed';
    if (this.reconnectTimer) {
      clearTimeout(this.reconnectTimer);
      this.reconnectTimer = null;
    }
    if (this.eventSource) {
      this.eventSource.close();
      this.eventSource = null;
    }
  }

  forceReconnect() {
    this.reconnectAttempts = 0;
    this.isIntentionallyClosed = false;
    this.connectionState = 'closed';
    this.disconnect();
    this.isIntentionallyClosed = false;
    this.connect();
  }

  attemptReconnect() {
    this.reconnectAttempts++;
    const delay = Math.min(
      this.maxReconnectDelay,
      this.reconnectDelay * Math.pow(2, this.reconnectAttempts - 1),
    );
    console.log(`[HTTP] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
    this.reconnectTimer = setTimeout(() => {
      this.reconnectTimer = null;
      this.connect();
    }, delay);
  }

  async send(data) {
    try {
      const resp = await fetch('/api/command', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify(data),
      });
      if (!resp.ok) {
        const err = await resp.json().catch(() => ({}));
        console.error('[HTTP] Command failed:', err.error || resp.statusText);
      }
    } catch (error) {
      console.error('[HTTP] Cannot send command:', error);
      this.dispatchEvent(new CustomEvent('error', { detail: error }));
    }
  }

  handleMessage(message) {
    if (!message || typeof message !== 'object') return;

    if (message.type === 'response') {
      if (!message.success && message.error) {
        this.dispatchEvent(new CustomEvent('serverError', { detail: { message: message.error } }));
      }
      return;
    }

    if (message.type === 'extension_ui_request' || message.type === 'agent_start' || message.type === 'agent_end' ||
        message.type === 'message_start' || message.type === 'message_update' || message.type === 'message_end' ||
        message.type === 'tool_execution_start' || message.type === 'tool_execution_update' ||
        message.type === 'tool_execution_end' || message.type === 'auto_compaction_start' ||
        message.type === 'auto_compaction_end' || message.type === 'extension_error' || message.type === 'session_name') {
      this.dispatchEvent(new CustomEvent('rpcEvent', { detail: message }));
      return;
    }

    console.warn('[HTTP] Unknown message type:', message.type);
  }
}
