import type { TracePayload } from "./models.js";

export interface BatchTransportOptions {
  apiKey: string;
  endpoint: string;
  maxBatchSize?: number;
  flushInterval?: number;
}

export class BatchTransport {
  private readonly apiKey: string;
  private readonly endpoint: string;
  private readonly maxBatchSize: number;
  private readonly flushInterval: number;
  private buffer: TracePayload[] = [];
  private timer: ReturnType<typeof setInterval> | null = null;

  constructor(options: BatchTransportOptions) {
    this.apiKey = options.apiKey;
    this.endpoint = options.endpoint.replace(/\/+$/, "");
    this.maxBatchSize = options.maxBatchSize ?? 10;
    this.flushInterval = options.flushInterval ?? 5_000;

    this.timer = setInterval(() => {
      void this._doFlush();
    }, this.flushInterval);
  }

  add(trace: TracePayload): void {
    const idx = this.buffer.findIndex((t) => t.id === trace.id);
    if (idx !== -1) {
      this.buffer[idx] = trace;
    } else {
      this.buffer.push(trace);
    }
    if (this.buffer.length >= this.maxBatchSize) {
      void this._doFlush();
    }
  }

  async flush(): Promise<void> {
    await this._doFlush();
  }

  async shutdown(): Promise<void> {
    if (this.timer !== null) {
      clearInterval(this.timer);
      this.timer = null;
    }
    await this._doFlush();
  }

  private async _doFlush(): Promise<void> {
    if (this.buffer.length === 0) {
      return;
    }

    const batch = this.buffer.splice(0, this.buffer.length);

    try {
      const response = await fetch(`${this.endpoint}/api/traces`, {
        method: "POST",
        headers: {
          Authorization: `Bearer ${this.apiKey}`,
          "Content-Type": "application/json",
        },
        body: JSON.stringify({ traces: batch }),
      });

      if (!response.ok) {
        await response.text().catch(() => "");
      }
    } catch {
    }
  }
}
