import { v4 as l } from "uuid";
const d = /* @__PURE__ */ new Map();
function E(n) {
  const e = n.baseUrl;
  let t = d.get(e);
  return t || (t = new g(n), d.set(e, t)), t;
}
class g {
  constructor(e) {
    this.config = e;
  }
  buildUrl(e, t, s) {
    let r = `${this.config.baseUrl}/${e}/${t}`;
    return s && (r += `/${s}`), r;
  }
  baseHeaders() {
    const e = {
      "Content-Type": "application/json"
    };
    return this.config.token && (e.Authorization = `Bearer ${this.config.token}`), e;
  }
  async fetchWithError(e, t) {
    const s = await fetch(e, t), r = await s.json();
    if (!s.ok)
      throw new Error(r.error?.message || "An error occurred");
    return r;
  }
  async getMetadata(e, t) {
    const s = this.buildUrl(e, t);
    return this.fetchWithError(s, {
      method: "GET",
      headers: this.baseHeaders()
    });
  }
  async read(e, t, s, r) {
    const i = typeof s == "number" || typeof s == "string" ? String(s) : void 0, a = this.buildUrl(e, t, i), c = {
      operation: "read",
      id: Array.isArray(s) ? s : void 0,
      options: r
    };
    return this.fetchWithError(a, {
      method: "POST",
      headers: this.baseHeaders(),
      body: JSON.stringify(c)
    });
  }
  async create(e, t, s, r) {
    const i = this.buildUrl(e, t), a = {
      operation: "create",
      data: s,
      options: r
    };
    return this.fetchWithError(i, {
      method: "POST",
      headers: this.baseHeaders(),
      body: JSON.stringify(a)
    });
  }
  async update(e, t, s, r, i) {
    const a = typeof r == "number" || typeof r == "string" ? String(r) : void 0, c = this.buildUrl(e, t, a), o = {
      operation: "update",
      id: Array.isArray(r) ? r : void 0,
      data: s,
      options: i
    };
    return this.fetchWithError(c, {
      method: "POST",
      headers: this.baseHeaders(),
      body: JSON.stringify(o)
    });
  }
  async delete(e, t, s) {
    const r = this.buildUrl(e, t, String(s)), i = {
      operation: "delete"
    };
    return this.fetchWithError(r, {
      method: "POST",
      headers: this.baseHeaders(),
      body: JSON.stringify(i)
    });
  }
}
const f = /* @__PURE__ */ new Map();
function _(n) {
  const e = n.url;
  let t = f.get(e);
  return t || (t = new p(n), f.set(e, t)), t;
}
class p {
  constructor(e) {
    this.ws = null, this.messageHandlers = /* @__PURE__ */ new Map(), this.subscriptions = /* @__PURE__ */ new Map(), this.eventListeners = {}, this.state = "disconnected", this.reconnectAttempts = 0, this.reconnectTimer = null, this.heartbeatTimer = null, this.isManualClose = !1, this.config = {
      url: e.url,
      reconnect: e.reconnect ?? !0,
      reconnectInterval: e.reconnectInterval ?? 3e3,
      maxReconnectAttempts: e.maxReconnectAttempts ?? 10,
      heartbeatInterval: e.heartbeatInterval ?? 3e4,
      debug: e.debug ?? !1
    };
  }
  async connect() {
    if (this.ws?.readyState === WebSocket.OPEN) {
      this.log("Already connected");
      return;
    }
    return this.isManualClose = !1, this.setState("connecting"), new Promise((e, t) => {
      try {
        this.ws = new WebSocket(this.config.url), this.ws.onopen = () => {
          this.log("Connected to WebSocket server"), this.setState("connected"), this.reconnectAttempts = 0, this.startHeartbeat(), this.emit("connect"), e();
        }, this.ws.onmessage = (s) => {
          this.handleMessage(s.data);
        }, this.ws.onerror = (s) => {
          this.log("WebSocket error:", s);
          const r = new Error("WebSocket connection error");
          this.emit("error", r), t(r);
        }, this.ws.onclose = (s) => {
          this.log("WebSocket closed:", s.code, s.reason), this.stopHeartbeat(), this.setState("disconnected"), this.emit("disconnect", s), this.config.reconnect && !this.isManualClose && this.reconnectAttempts < this.config.maxReconnectAttempts && (this.reconnectAttempts++, this.log(`Reconnection attempt ${this.reconnectAttempts}/${this.config.maxReconnectAttempts}`), this.setState("reconnecting"), this.reconnectTimer = setTimeout(() => {
            this.connect().catch((r) => {
              this.log("Reconnection failed:", r);
            });
          }, this.config.reconnectInterval));
        };
      } catch (s) {
        t(s);
      }
    });
  }
  disconnect() {
    this.isManualClose = !0, this.reconnectTimer && (clearTimeout(this.reconnectTimer), this.reconnectTimer = null), this.stopHeartbeat(), this.ws && (this.setState("disconnecting"), this.ws.close(), this.ws = null), this.setState("disconnected"), this.messageHandlers.clear();
  }
  async request(e, t, s) {
    this.ensureConnected();
    const r = l(), i = {
      id: r,
      type: "request",
      operation: e,
      entity: t,
      schema: s?.schema,
      record_id: s?.record_id,
      data: s?.data,
      options: s?.options
    };
    return new Promise((a, c) => {
      this.messageHandlers.set(r, (o) => {
        o.success ? a(o.data) : c(new Error(o.error?.message || "Request failed"));
      }), this.send(i), setTimeout(() => {
        this.messageHandlers.has(r) && (this.messageHandlers.delete(r), c(new Error("Request timeout")));
      }, 3e4);
    });
  }
  async read(e, t) {
    return this.request("read", e, {
      schema: t?.schema,
      record_id: t?.record_id,
      options: {
        filters: t?.filters,
        columns: t?.columns,
        sort: t?.sort,
        preload: t?.preload,
        limit: t?.limit,
        offset: t?.offset
      }
    });
  }
  async create(e, t, s) {
    return this.request("create", e, {
      schema: s?.schema,
      data: t
    });
  }
  async update(e, t, s, r) {
    return this.request("update", e, {
      schema: r?.schema,
      record_id: t,
      data: s
    });
  }
  async delete(e, t, s) {
    await this.request("delete", e, {
      schema: s?.schema,
      record_id: t
    });
  }
  async meta(e, t) {
    return this.request("meta", e, {
      schema: t?.schema
    });
  }
  async subscribe(e, t, s) {
    this.ensureConnected();
    const r = l(), i = {
      id: r,
      type: "subscription",
      operation: "subscribe",
      entity: e,
      schema: s?.schema,
      options: {
        filters: s?.filters
      }
    };
    return new Promise((a, c) => {
      this.messageHandlers.set(r, (o) => {
        if (o.success && o.data?.subscription_id) {
          const h = o.data.subscription_id;
          this.subscriptions.set(h, {
            id: h,
            entity: e,
            schema: s?.schema,
            options: { filters: s?.filters },
            callback: t
          }), this.log(`Subscribed to ${e} with ID: ${h}`), a(h);
        } else
          c(new Error(o.error?.message || "Subscription failed"));
      }), this.send(i), setTimeout(() => {
        this.messageHandlers.has(r) && (this.messageHandlers.delete(r), c(new Error("Subscription timeout")));
      }, 1e4);
    });
  }
  async unsubscribe(e) {
    this.ensureConnected();
    const t = l(), s = {
      id: t,
      type: "subscription",
      operation: "unsubscribe",
      subscription_id: e
    };
    return new Promise((r, i) => {
      this.messageHandlers.set(t, (a) => {
        a.success ? (this.subscriptions.delete(e), this.log(`Unsubscribed from ${e}`), r()) : i(new Error(a.error?.message || "Unsubscribe failed"));
      }), this.send(s), setTimeout(() => {
        this.messageHandlers.has(t) && (this.messageHandlers.delete(t), i(new Error("Unsubscribe timeout")));
      }, 1e4);
    });
  }
  getSubscriptions() {
    return Array.from(this.subscriptions.values());
  }
  getState() {
    return this.state;
  }
  isConnected() {
    return this.ws?.readyState === WebSocket.OPEN;
  }
  on(e, t) {
    this.eventListeners[e] = t;
  }
  off(e) {
    delete this.eventListeners[e];
  }
  // Private methods
  handleMessage(e) {
    try {
      const t = JSON.parse(e);
      switch (this.log("Received message:", t), this.emit("message", t), t.type) {
        case "response":
          this.handleResponse(t);
          break;
        case "notification":
          this.handleNotification(t);
          break;
        case "pong":
          break;
        default:
          this.log("Unknown message type:", t.type);
      }
    } catch (t) {
      this.log("Error parsing message:", t);
    }
  }
  handleResponse(e) {
    const t = this.messageHandlers.get(e.id);
    t && (t(e), this.messageHandlers.delete(e.id));
  }
  handleNotification(e) {
    const t = this.subscriptions.get(e.subscription_id);
    t?.callback && t.callback(e);
  }
  send(e) {
    if (!this.ws || this.ws.readyState !== WebSocket.OPEN)
      throw new Error("WebSocket is not connected");
    const t = JSON.stringify(e);
    this.log("Sending message:", e), this.ws.send(t);
  }
  startHeartbeat() {
    this.heartbeatTimer || (this.heartbeatTimer = setInterval(() => {
      if (this.isConnected()) {
        const e = {
          id: l(),
          type: "ping"
        };
        this.send(e);
      }
    }, this.config.heartbeatInterval));
  }
  stopHeartbeat() {
    this.heartbeatTimer && (clearInterval(this.heartbeatTimer), this.heartbeatTimer = null);
  }
  setState(e) {
    this.state !== e && (this.state = e, this.emit("stateChange", e));
  }
  ensureConnected() {
    if (!this.isConnected())
      throw new Error("WebSocket is not connected. Call connect() first.");
  }
  emit(e, ...t) {
    const s = this.eventListeners[e];
    s && s(...t);
  }
  log(...e) {
    this.config.debug && console.log("[WebSocketClient]", ...e);
  }
}
function v(n) {
  return typeof btoa == "function" ? "ZIP_" + btoa(n) : "ZIP_" + Buffer.from(n, "utf-8").toString("base64");
}
function w(n) {
  let e = n;
  return e.startsWith("ZIP_") ? (e = e.slice(4).replace(/[\n\r ]/g, ""), e = m(e)) : e.startsWith("__") && (e = e.slice(2).replace(/[\n\r ]/g, ""), e = m(e)), (e.startsWith("ZIP_") || e.startsWith("__")) && (e = w(e)), e;
}
function m(n) {
  return typeof atob == "function" ? atob(n) : Buffer.from(n, "base64").toString("utf-8");
}
function u(n) {
  const e = {};
  if (n.columns?.length && (e["X-Select-Fields"] = n.columns.join(",")), n.omit_columns?.length && (e["X-Not-Select-Fields"] = n.omit_columns.join(",")), n.filters?.length)
    for (const t of n.filters) {
      const s = t.logic_operator ?? "AND", r = y(t.operator), i = S(t);
      t.operator === "eq" && s === "AND" ? e[`X-FieldFilter-${t.column}`] = i : s === "OR" ? e[`X-SearchOr-${r}-${t.column}`] = i : e[`X-SearchOp-${r}-${t.column}`] = i;
    }
  if (n.sort?.length) {
    const t = n.sort.map((s) => s.direction.toUpperCase() === "DESC" ? `-${s.column}` : `+${s.column}`);
    e["X-Sort"] = t.join(",");
  }
  if (n.limit !== void 0 && (e["X-Limit"] = String(n.limit)), n.offset !== void 0 && (e["X-Offset"] = String(n.offset)), n.cursor_forward && (e["X-Cursor-Forward"] = n.cursor_forward), n.cursor_backward && (e["X-Cursor-Backward"] = n.cursor_backward), n.preload?.length) {
    const t = n.preload.map((s) => s.columns?.length ? `${s.relation}:${s.columns.join(",")}` : s.relation);
    e["X-Preload"] = t.join("|");
  }
  if (n.fetch_row_number && (e["X-Fetch-RowNumber"] = n.fetch_row_number), n.computedColumns?.length)
    for (const t of n.computedColumns)
      e[`X-CQL-SEL-${t.name}`] = t.expression;
  if (n.customOperators?.length) {
    const t = n.customOperators.map(
      (s) => s.sql
    );
    e["X-Custom-SQL-W"] = t.join(" AND ");
  }
  return e;
}
function y(n) {
  switch (n) {
    case "eq":
      return "equals";
    case "neq":
      return "notequals";
    case "gt":
      return "greaterthan";
    case "gte":
      return "greaterthanorequal";
    case "lt":
      return "lessthan";
    case "lte":
      return "lessthanorequal";
    case "like":
    case "ilike":
    case "contains":
      return "contains";
    case "startswith":
      return "beginswith";
    case "endswith":
      return "endswith";
    case "in":
      return "in";
    case "between":
      return "between";
    case "between_inclusive":
      return "betweeninclusive";
    case "is_null":
      return "empty";
    case "is_not_null":
      return "notempty";
    default:
      return n;
  }
}
function S(n) {
  return n.value === null || n.value === void 0 ? "" : Array.isArray(n.value) ? n.value.join(",") : String(n.value);
}
const b = /* @__PURE__ */ new Map();
function C(n) {
  const e = n.baseUrl;
  let t = b.get(e);
  return t || (t = new H(n), b.set(e, t)), t;
}
class H {
  constructor(e) {
    this.config = e;
  }
  buildUrl(e, t, s) {
    let r = `${this.config.baseUrl}/${e}/${t}`;
    return s && (r += `/${s}`), r;
  }
  baseHeaders() {
    const e = {
      "Content-Type": "application/json"
    };
    return this.config.token && (e.Authorization = `Bearer ${this.config.token}`), e;
  }
  async fetchWithError(e, t) {
    const s = await fetch(e, t), r = await s.json();
    if (!s.ok)
      throw new Error(
        r.error?.message || `${s.statusText} (${s.status})`
      );
    return {
      data: r,
      success: !0,
      error: r.error ? r.error : void 0,
      metadata: {
        count: s.headers.get("content-range") ? Number(s.headers.get("content-range")?.split("/")[1]) : 0,
        total: s.headers.get("content-range") ? Number(s.headers.get("content-range")?.split("/")[1]) : 0,
        filtered: s.headers.get("content-range") ? Number(s.headers.get("content-range")?.split("/")[1]) : 0,
        offset: s.headers.get("content-range") ? Number(
          s.headers.get("content-range")?.split("/")[0].split("-")[0]
        ) : 0,
        limit: s.headers.get("x-limit") ? Number(s.headers.get("x-limit")) : 0
      }
    };
  }
  async read(e, t, s, r) {
    const i = this.buildUrl(e, t, s), a = r ? u(r) : {};
    return this.fetchWithError(i, {
      method: "GET",
      headers: { ...this.baseHeaders(), ...a }
    });
  }
  async create(e, t, s, r) {
    const i = this.buildUrl(e, t), a = r ? u(r) : {};
    return this.fetchWithError(i, {
      method: "POST",
      headers: { ...this.baseHeaders(), ...a },
      body: JSON.stringify(s)
    });
  }
  async update(e, t, s, r, i) {
    const a = this.buildUrl(e, t, s), c = i ? u(i) : {};
    return this.fetchWithError(a, {
      method: "PUT",
      headers: { ...this.baseHeaders(), ...c },
      body: JSON.stringify(r)
    });
  }
  async delete(e, t, s) {
    const r = this.buildUrl(e, t, s);
    return this.fetchWithError(r, {
      method: "DELETE",
      headers: this.baseHeaders()
    });
  }
}
export {
  H as HeaderSpecClient,
  g as ResolveSpecClient,
  p as WebSocketClient,
  u as buildHeaders,
  w as decodeHeaderValue,
  v as encodeHeaderValue,
  C as getHeaderSpecClient,
  E as getResolveSpecClient,
  _ as getWebSocketClient
};
