/**
 * AgentForms SDK — lightweight client for the AI Workflow Builder SSE endpoint.
 *
 * Usage:
 *   const af = new AgentForms({ baseUrl: 'https://agentforms.io', apiKey: 'afk_live_...' });
 *   await af.buildWorkflow({ prompt: 'Contact form with name, email, message, send to webhook' }, {
 *     onToken: (token) => console.log(token),
 *     onComplete: (workflow) => console.log('Built:', workflow),
 *     onError: (error) => console.error('Failed:', error),
 *   });
 *
 * No dependencies. Works in browser and Node.js (with event-source-polyfill for Node).
 */

class AgentForms {
  /**
   * @param {Object} options
   * @param {string} options.baseUrl - API base URL (e.g. 'https://agentforms.io')
   * @param {string} options.apiKey - API key for authentication
   */
  constructor(options) {
    if (!options || !options.baseUrl || !options.apiKey) {
      throw new Error('AgentForms requires baseUrl and apiKey');
    }
    this.baseUrl = options.baseUrl.replace(/\/$/, '');
    this.apiKey = options.apiKey;
  }

  /**
   * Build a workflow using the streaming SSE endpoint.
   *
   * @param {Object} params
   * @param {string} params.prompt - Natural language description of the workflow
   * @param {string} [params.form_name] - Optional form name override
   * @param {Object} callbacks
   * @param {Function} [callbacks.onToken] - Called with each token chunk from LLM
   * @param {Function} [callbacks.onFields] - Called when fields are parsed (subset of complete)
   * @param {Function} [callbacks.onActions] - Called when actions are parsed (subset of complete)
   * @param {Function} [callbacks.onComplete] - Called with full workflow definition
   * @param {Function} [callbacks.onError] - Called on error with error message
   * @returns {Promise<void>}
   */
  buildWorkflow(params, callbacks) {
    const { prompt, form_name } = params || {};
    const { onToken, onFields, onActions, onComplete, onError } = callbacks || {};

    if (!prompt || prompt.length < 5) {
      const err = new Error('Prompt must be at least 5 characters');
      if (onError) onError(err.message);
      throw err;
    }

    return new Promise((resolve, reject) => {
      const url = `${this.baseUrl}/api/v2/forms/build/stream`;

      // Use EventSource with POST support via fetch + ReadableStream
      // since EventSource only supports GET
      fetch(url, {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'Authorization': `Bearer ${this.apiKey}`,
        },
        body: JSON.stringify({ prompt, form_name }),
      })
      .then(response => {
        if (!response.ok) {
          return response.json().then(err => {
            const msg = err.error || `HTTP ${response.status}`;
            if (onError) onError(msg);
            throw new Error(msg);
          });
        }

        const reader = response.body.getReader();
        const decoder = new TextDecoder();
        let buffer = '';

        const readChunk = () => {
          return reader.read().then(({ done, value }) => {
            if (done) {
              resolve();
              return;
            }

            buffer += decoder.decode(value, { stream: true });
            this._parseSSE(buffer, onToken, onFields, onActions, onComplete, onError, () => {
              // After parsing, clear processed buffer
              const lastDoubleNewline = buffer.lastIndexOf('\n\n');
              if (lastDoubleNewline !== -1) {
                buffer = buffer.slice(lastDoubleNewline + 2);
              }
              readChunk();
            });
          });
        };

        readChunk();
      })
      .catch(err => {
        if (onError) onError(err.message);
        reject(err);
      });
    });
  }

  /**
   * Parse SSE events from a buffer string.
   * @private
   */
  _parseSSE(buffer, onToken, onFields, onActions, onComplete, onError, onMore) {
    const events = [];
    const lines = buffer.split('\n');
    let currentEvent = null;
    let currentData = '';

    for (const line of lines) {
      if (line.startsWith('event: ')) {
        // Save previous event if exists
        if (currentEvent && currentData) {
          events.push({ type: currentEvent, data: currentData });
        }
        currentEvent = line.slice(7).trim();
        currentData = '';
      } else if (line.startsWith('data: ')) {
        currentData += line.slice(6);
      }
    }

    // Save last event
    if (currentEvent && currentData) {
      events.push({ type: currentEvent, data: currentData });
    }

    for (const event of events) {
      this._handleEvent(event, onToken, onFields, onActions, onComplete, onError);
    }

    if (onMore) onMore();
  }

  /**
   * Handle a single SSE event.
   * @private
   */
  _handleEvent(event, onToken, onFields, onActions, onComplete, onError) {
    try {
      const data = typeof event.data === 'string' ? JSON.parse(event.data) : event.data;

      switch (event.type) {
        case 'progress':
          if (onToken) onToken(data);
          break;
        case 'complete':
          // Fire field/action callbacks if present
          if (onFields && data.fields) onFields(data.fields);
          if (onActions && data.actions) onActions(data.actions);
          if (onComplete) onComplete(data);
          break;
        case 'error':
          if (onError) onError(data);
          break;
      }
    } catch (err) {
      if (onError) onError(`Failed to parse SSE event: ${err.message}`);
    }
  }
}

// Export for different environments
if (typeof module !== 'undefined' && module.exports) {
  module.exports = { AgentForms };
} else if (typeof window !== 'undefined') {
  window.AgentForms = AgentForms;
}