(function() {
  function text(id) {
    var element = document.getElementById(id);
    return element ? String(element.value || '').trim() : '';
  }

  function number(id) {
    var value = text(id);
    if (!value) return null;
    var parsed = Number(value);
    return Number.isFinite(parsed) ? parsed : null;
  }

  function lines(id) {
    var value = text(id);
    return value
      ? value.split('\n').map(function(item) { return item.trim(); }).filter(Boolean)
      : [];
  }

  function checked(id) {
    var element = document.getElementById(id);
    return !!(element && element.checked);
  }

  function selectedMode() {
    return text('streaming-mode') || 'unary';
  }

  function serializeStreamingConfig() {
    if (selectedMode() === 'unary') {
      return null;
    }

    var config = {
      mode: selectedMode(),
      transport_behavior: text('streaming-transport-behavior') || 'request_response',
      aggregation_mode: text('streaming-aggregation-mode') || 'summary_plus_samples',
      window_duration_ms: number('streaming-window-duration-ms'),
      poll_interval_ms: number('streaming-poll-interval-ms'),
      upstream_timeout_ms: number('streaming-upstream-timeout-ms'),
      idle_timeout_ms: number('streaming-idle-timeout-ms'),
      max_session_lifetime_ms: number('streaming-session-lifetime-ms'),
      max_items: number('streaming-max-items'),
      max_bytes: number('streaming-max-bytes'),
      max_field_length: number('streaming-max-field-length'),
      sampling_rate: number('streaming-sampling-rate'),
      items_path: text('streaming-items-path') || null,
      summary_path: text('streaming-summary-path') || null,
      done_path: text('streaming-done-path') || null,
      cursor_path: text('streaming-cursor-path') || null,
      status_path: text('streaming-status-path') || null,
      redacted_paths: lines('streaming-redacted-paths'),
      truncate_item_fields: checked('streaming-truncate-item-fields'),
      drop_duplicates: checked('streaming-drop-duplicates'),
      tool_family: {},
    };

    if (config.mode === 'session') {
      config.tool_family.start_tool_name = text('streaming-start-tool-name') || null;
      config.tool_family.poll_tool_name = text('streaming-poll-tool-name') || null;
      config.tool_family.stop_tool_name = text('streaming-stop-tool-name') || null;
    } else if (config.mode === 'async_job') {
      config.tool_family.start_tool_name = text('streaming-start-tool-name') || null;
      config.tool_family.status_tool_name = text('streaming-status-tool-name') || null;
      config.tool_family.result_tool_name = text('streaming-result-tool-name') || null;
      config.tool_family.cancel_tool_name = text('streaming-cancel-tool-name') || null;
    }

    return config;
  }

  function validateStreamingConfig(capabilities) {
    var config = serializeStreamingConfig();
    if (!config) {
      return { valid: true, errors: [] };
    }

    var errors = [];
    var capability = (capabilities || []).find(function(item) {
      return item.protocol === window.wizardProtocol;
    });

    if (capability && Array.isArray(capability.supports_execution_modes)) {
      var supported = capability.supports_execution_modes.map(String);
      if (supported.indexOf(config.mode) === -1) {
        errors.push('Selected execution mode is not supported by the current protocol.');
      }
    }

    if (!config.max_items || config.max_items <= 0) {
      errors.push('Max items must be a positive integer.');
    }

    if (!config.max_bytes || config.max_bytes <= 0) {
      errors.push('Max bytes must be a positive integer.');
    }

    if (config.mode === 'window' && (!config.window_duration_ms || config.window_duration_ms <= 0)) {
      errors.push('Window duration must be set for window mode.');
    }

    if (config.mode === 'session' && (!config.poll_interval_ms || config.poll_interval_ms <= 0)) {
      errors.push('Poll interval must be set for session mode.');
    }

    if (config.mode === 'async_job' && (!config.max_session_lifetime_ms || config.max_session_lifetime_ms <= 0)) {
      errors.push('Session lifetime must be set for async job mode.');
    }

    return {
      valid: errors.length === 0,
      errors: errors,
      config: config,
    };
  }

  window.CrankStreamingForm = {
    serializeStreamingConfig: serializeStreamingConfig,
    deserializeStreamingConfig: function(streaming) {
      if (typeof window.applyStreamingConfig === 'function') {
        window.applyStreamingConfig(streaming);
      }
    },
    validateStreamingConfig: validateStreamingConfig,
  };
}());
