import type { LLMProvider } from '../types';
import { generateOpenAIStyle } from './openai';
import { assertSafeProviderUrl } from '../safeUrl';

/**
 * SparkControl — a self-hosted local-inference gateway (the operator's own
 * StartOS package). Its LLM surface is OpenAI-compatible
 * (`POST {baseUrl}/chat/completions`, SSE `data:` frames, `[DONE]`), so we
 * reuse the OpenAI-style streamer wholesale.
 *
 * Two differences from the generic `openai-compatible` provider:
 *   1. **No API key.** SparkControl takes no auth on the LAN, so the key is
 *      optional (`requireApiKey: false`) — the streamer omits the
 *      Authorization header when none is set.
 *   2. **Reached over the internal same-box address** (e.g.
 *      `http://spark-control.startos:9999/v1`) — plain HTTP, no TLS to worry
 *      about. The public LAN interface is HTTPS with a self-signed Start9
 *      cert; we deliberately don't go there, so no cert-verification games.
 *
 * Custom base URL ⇒ SSRF-guarded + admin-only, same as Ollama. The model name
 * is whatever vLLM currently has loaded; the Settings UI auto-detects it via
 * SparkControl's `/api/endpoints` discovery (see app/api/ai/sparkcontrol/model).
 */
export const sparkcontrol: LLMProvider = {
  id: 'sparkcontrol',
  label: 'SparkControl (local)',
  requiresApiKey: false,
  requiresBaseUrl: true,
  async *generate(opts) {
    if (!opts.baseUrl) {
      yield {
        type: 'error',
        message:
          'Base URL is required (e.g. http://spark-control.startos:9999/v1).',
      };
      return;
    }
    // User-supplied base URL → SSRF guard (private-LAN + loopback allowed on
    // purpose; reaching spark-control.startos is the feature).
    try {
      await assertSafeProviderUrl(opts.baseUrl);
    } catch (e) {
      yield { type: 'error', message: `SparkControl: ${(e as Error).message}` };
      return;
    }
    yield* generateOpenAIStyle(opts, opts.baseUrl, 'SparkControl', {
      requireApiKey: false,
    });
  },
};
