import { createRequire } from 'module';
import 'fs';
import 'path';

// src/chat/sqlite/factory.ts

// src/chat/types.ts
function createChatId() {
  return crypto.randomUUID();
}

// src/errors.ts
var AgentSDKError = class extends Error {
  /** @internal Marker for cross-bundle identity checks */
  _agentSDKError = true;
  /** Machine-readable error code. Prefer values from the ErrorCode enum. */
  code;
  /** Whether this error is safe to retry */
  retryable;
  /** HTTP status code hint for error classification */
  httpStatus;
  constructor(message, options) {
    super(message, options);
    this.name = "AgentSDKError";
    this.code = options?.code;
    this.retryable = options?.retryable ?? false;
    this.httpStatus = options?.httpStatus;
  }
  /** Check if an error is an AgentSDKError (works across bundled copies) */
  static is(error) {
    return error instanceof Error && "_agentSDKError" in error && error._agentSDKError === true;
  }
};

// src/chat/storage.ts
var StorageError = class extends AgentSDKError {
  /** Machine-readable error code from the unified ErrorCode enum */
  code;
  constructor(message, code) {
    super(message);
    this.name = "StorageError";
    this.code = code;
  }
};

// src/chat/sqlite/session-store.ts
var CREATE_SESSIONS_TABLE = `
  CREATE TABLE IF NOT EXISTS sessions (
    id TEXT PRIMARY KEY,
    title TEXT,
    config TEXT NOT NULL,
    metadata TEXT NOT NULL,
    status TEXT NOT NULL DEFAULT 'active',
    backend_session_id TEXT,
    created_at TEXT NOT NULL,
    updated_at TEXT NOT NULL
  )
`;
var CREATE_MESSAGES_TABLE = `
  CREATE TABLE IF NOT EXISTS messages (
    id TEXT PRIMARY KEY,
    session_id TEXT NOT NULL,
    role TEXT NOT NULL,
    parts TEXT NOT NULL,
    metadata TEXT,
    status TEXT NOT NULL DEFAULT 'complete',
    created_at TEXT NOT NULL,
    updated_at TEXT,
    position INTEGER NOT NULL,
    FOREIGN KEY (session_id) REFERENCES sessions(id) ON DELETE CASCADE
  )
`;
var CREATE_MESSAGES_SESSION_IDX = `
  CREATE INDEX IF NOT EXISTS idx_messages_session ON messages(session_id, position)
`;
var SQLiteSessionStore = class {
  db;
  constructor(db) {
    this.db = db;
    this.db.exec(CREATE_SESSIONS_TABLE);
    this.db.exec(CREATE_MESSAGES_TABLE);
    this.db.exec(CREATE_MESSAGES_SESSION_IDX);
  }
  async createSession(options = {}) {
    const id = createChatId();
    const now = (/* @__PURE__ */ new Date()).toISOString();
    const config = {
      model: "default",
      backend: "default",
      ...options.config
    };
    const metadata = {
      messageCount: 0,
      totalTokens: 0,
      tags: options.tags,
      custom: options.custom
    };
    this.db.prepare(`
      INSERT INTO sessions (id, title, config, metadata, status, created_at, updated_at)
      VALUES (?, ?, ?, ?, 'active', ?, ?)
    `).run(id, options.title ?? null, JSON.stringify(config), JSON.stringify(metadata), now, now);
    return this.buildSession(id, options.title, config, metadata, "active", now, now, []);
  }
  async getSession(id) {
    const row = this.db.prepare("SELECT * FROM sessions WHERE id = ?").get(id);
    if (!row) return null;
    const messages = this.loadAllMessages(row.id);
    return this.rowToSession(row, messages);
  }
  async listSessions(options) {
    const rows = this.db.prepare("SELECT * FROM sessions ORDER BY updated_at DESC").all();
    let sessions = rows.map((r) => this.rowToSession(r, []));
    if (options?.filter) sessions = sessions.filter(options.filter);
    if (options?.sort) sessions.sort(options.sort);
    if (options?.offset) sessions = sessions.slice(options.offset);
    if (options?.limit) sessions = sessions.slice(0, options.limit);
    return sessions;
  }
  async updateTitle(id, title) {
    const result = this.db.prepare(
      "UPDATE sessions SET title = ?, updated_at = ? WHERE id = ?"
    ).run(title, (/* @__PURE__ */ new Date()).toISOString(), id);
    if (result.changes === 0) throw new StorageError(`Session not found: ${id}`, "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */);
  }
  async updateConfig(id, config) {
    const row = this.db.prepare("SELECT config FROM sessions WHERE id = ?").get(id);
    if (!row) throw new StorageError(`Session not found: ${id}`, "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */);
    const merged = { ...JSON.parse(row.config), ...config };
    this.db.prepare(
      "UPDATE sessions SET config = ?, updated_at = ? WHERE id = ?"
    ).run(JSON.stringify(merged), (/* @__PURE__ */ new Date()).toISOString(), id);
  }
  async deleteSession(id) {
    const result = this.db.prepare("DELETE FROM sessions WHERE id = ?").run(id);
    if (result.changes === 0) throw new StorageError(`Session not found: ${id}`, "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */);
  }
  async appendMessage(sessionId, message) {
    const session = this.db.prepare("SELECT id FROM sessions WHERE id = ?").get(sessionId);
    if (!session) throw new StorageError(`Session not found: ${sessionId}`, "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */);
    const position = this.getNextPosition(sessionId);
    this.db.prepare(`
      INSERT INTO messages (id, session_id, role, parts, metadata, status, created_at, updated_at, position)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
    `).run(
      message.id,
      sessionId,
      message.role,
      JSON.stringify(message.parts),
      message.metadata ? JSON.stringify(message.metadata) : null,
      message.status,
      message.createdAt,
      message.updatedAt ?? null,
      position
    );
    this.incrementMessageCount(sessionId);
  }
  async saveMessages(sessionId, messages) {
    if (messages.length === 0) return;
    const session = this.db.prepare("SELECT id FROM sessions WHERE id = ?").get(sessionId);
    if (!session) throw new StorageError(`Session not found: ${sessionId}`, "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */);
    const insertMsg = this.db.prepare(`
      INSERT INTO messages (id, session_id, role, parts, metadata, status, created_at, updated_at, position)
      VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)
    `);
    const tx = this.db.transaction(() => {
      let pos = this.getNextPosition(sessionId);
      for (const msg of messages) {
        insertMsg.run(
          msg.id,
          sessionId,
          msg.role,
          JSON.stringify(msg.parts),
          msg.metadata ? JSON.stringify(msg.metadata) : null,
          msg.status,
          msg.createdAt,
          msg.updatedAt ?? null,
          pos++
        );
      }
      this.updateSessionMeta(sessionId, messages.length);
    });
    tx();
  }
  async loadMessages(sessionId, options) {
    const session = this.db.prepare("SELECT id FROM sessions WHERE id = ?").get(sessionId);
    if (!session) throw new StorageError(`Session not found: ${sessionId}`, "STORAGE_NOT_FOUND" /* STORAGE_NOT_FOUND */);
    const total = this.db.prepare(
      "SELECT COUNT(*) as cnt FROM messages WHERE session_id = ?"
    ).get(sessionId).cnt;
    const limit = options?.limit ?? 50;
    const offset = options?.offset ?? 0;
    const rows = this.db.prepare(
      "SELECT * FROM messages WHERE session_id = ? ORDER BY position ASC LIMIT ? OFFSET ?"
    ).all(sessionId, limit, offset);
    return {
      messages: rows.map(rowToMessage),
      total,
      hasMore: offset + limit < total
    };
  }
  async searchSessions(options) {
    const pattern = `%${options.query}%`;
    const limit = options.limit ?? 20;
    const titleMatches = this.db.prepare(
      "SELECT * FROM sessions WHERE title LIKE ? COLLATE NOCASE LIMIT ?"
    ).all(pattern, limit);
    const contentMatches = this.db.prepare(`
      SELECT DISTINCT s.* FROM sessions s
      JOIN messages m ON m.session_id = s.id
      WHERE m.parts LIKE ? COLLATE NOCASE
      LIMIT ?
    `).all(pattern, limit);
    const seen = /* @__PURE__ */ new Set();
    const results = [];
    for (const row of [...titleMatches, ...contentMatches]) {
      if (!seen.has(row.id)) {
        seen.add(row.id);
        results.push(this.rowToSession(row, []));
      }
    }
    return results.slice(0, limit);
  }
  async count() {
    return this.db.prepare("SELECT COUNT(*) as cnt FROM sessions").get().cnt;
  }
  async clear() {
    this.db.exec("DELETE FROM messages");
    this.db.exec("DELETE FROM sessions");
  }
  // ─── Private Helpers ─────────────────────────────────────────
  getNextPosition(sessionId) {
    const result = this.db.prepare(
      "SELECT MAX(position) as maxPos FROM messages WHERE session_id = ?"
    ).get(sessionId);
    return (result.maxPos ?? -1) + 1;
  }
  incrementMessageCount(sessionId) {
    this.db.prepare(`
      UPDATE sessions
      SET metadata = json_set(metadata, '$.messageCount', json_extract(metadata, '$.messageCount') + 1),
          updated_at = ?
      WHERE id = ?
    `).run((/* @__PURE__ */ new Date()).toISOString(), sessionId);
  }
  updateSessionMeta(sessionId, addedCount) {
    this.db.prepare(`
      UPDATE sessions
      SET metadata = json_set(metadata, '$.messageCount', json_extract(metadata, '$.messageCount') + ?),
          updated_at = ?
      WHERE id = ?
    `).run(addedCount, (/* @__PURE__ */ new Date()).toISOString(), sessionId);
  }
  loadAllMessages(sessionId) {
    const rows = this.db.prepare(
      "SELECT * FROM messages WHERE session_id = ? ORDER BY position ASC"
    ).all(sessionId);
    return rows.map(rowToMessage);
  }
  rowToSession(row, messages) {
    return this.buildSession(
      row.id,
      row.title,
      JSON.parse(row.config),
      JSON.parse(row.metadata),
      row.status,
      row.created_at,
      row.updated_at,
      messages
    );
  }
  buildSession(id, title, config, metadata, status, createdAt, updatedAt, messages) {
    return {
      id,
      title: title ?? void 0,
      messages,
      config,
      metadata,
      status,
      createdAt,
      updatedAt
    };
  }
};
function rowToMessage(row) {
  return {
    id: row.id,
    role: row.role,
    parts: JSON.parse(row.parts),
    metadata: row.metadata ? JSON.parse(row.metadata) : void 0,
    status: row.status,
    createdAt: row.created_at,
    updatedAt: row.updated_at ?? void 0
  };
}

// src/chat/sqlite/provider-store.ts
var CREATE_PROVIDERS_TABLE = `
  CREATE TABLE IF NOT EXISTS providers (
    id TEXT PRIMARY KEY,
    backend TEXT NOT NULL,
    model TEXT NOT NULL,
    label TEXT NOT NULL,
    created_at INTEGER NOT NULL
  )
`;
var SQLiteProviderStore = class {
  db;
  constructor(db) {
    this.db = db;
    this.db.exec(CREATE_PROVIDERS_TABLE);
  }
  async create(config) {
    this.db.prepare(`
      INSERT INTO providers (id, backend, model, label, created_at)
      VALUES (?, ?, ?, ?, ?)
    `).run(config.id, config.backend, config.model, config.label, config.createdAt);
  }
  async get(id) {
    const row = this.db.prepare("SELECT * FROM providers WHERE id = ?").get(id);
    return row ? rowToProvider(row) : null;
  }
  async update(id, changes) {
    const existing = this.db.prepare("SELECT id FROM providers WHERE id = ?").get(id);
    if (!existing) throw new Error(`Provider "${id}" not found`);
    const sets = [];
    const values = [];
    if (changes.backend !== void 0) {
      sets.push("backend = ?");
      values.push(changes.backend);
    }
    if (changes.model !== void 0) {
      sets.push("model = ?");
      values.push(changes.model);
    }
    if (changes.label !== void 0) {
      sets.push("label = ?");
      values.push(changes.label);
    }
    if (sets.length > 0) {
      values.push(id);
      this.db.prepare(`UPDATE providers SET ${sets.join(", ")} WHERE id = ?`).run(...values);
    }
  }
  async delete(id) {
    this.db.prepare("DELETE FROM providers WHERE id = ?").run(id);
  }
  async list() {
    const rows = this.db.prepare("SELECT * FROM providers ORDER BY created_at ASC").all();
    return rows.map(rowToProvider);
  }
};
function rowToProvider(row) {
  return {
    id: row.id,
    backend: row.backend,
    model: row.model,
    label: row.label,
    createdAt: row.created_at
  };
}

// src/chat/sqlite/token-store.ts
var CREATE_TOKENS_TABLE = `
  CREATE TABLE IF NOT EXISTS tokens (
    provider TEXT PRIMARY KEY,
    token_json TEXT NOT NULL,
    saved_at INTEGER NOT NULL
  )
`;
var SQLiteTokenStore = class {
  db;
  constructor(db) {
    this.db = db;
    this.db.exec(CREATE_TOKENS_TABLE);
  }
  async save(provider, token) {
    this.db.prepare(`
      INSERT OR REPLACE INTO tokens (provider, token_json, saved_at)
      VALUES (?, ?, ?)
    `).run(provider, JSON.stringify(token), Date.now());
  }
  async load(provider) {
    const row = this.db.prepare("SELECT token_json FROM tokens WHERE provider = ?").get(provider);
    return row ? JSON.parse(row.token_json) : null;
  }
  async clear(provider) {
    this.db.prepare("DELETE FROM tokens WHERE provider = ?").run(provider);
  }
  async clearAll() {
    this.db.exec("DELETE FROM tokens");
  }
  async list() {
    const rows = this.db.prepare("SELECT provider FROM tokens ORDER BY saved_at ASC").all();
    return rows.map((r) => r.provider);
  }
};

// src/chat/sqlite/factory.ts
function createSQLiteStorage(pathOrOptions) {
  let db;
  if (typeof pathOrOptions === "string") {
    db = createDatabase(pathOrOptions);
  } else if (pathOrOptions.db) {
    db = pathOrOptions.db;
  } else {
    db = createDatabase(pathOrOptions.dbPath);
  }
  db.pragma("journal_mode = WAL");
  db.pragma("foreign_keys = ON");
  return {
    db,
    sessionStore: new SQLiteSessionStore(db),
    providerStore: new SQLiteProviderStore(db),
    tokenStore: new SQLiteTokenStore(db)
  };
}
function createDatabase(dbPath) {
  try {
    const esmRequire = createRequire(import.meta.url);
    const BetterSqlite3 = esmRequire("better-sqlite3");
    return new BetterSqlite3(dbPath);
  } catch (err) {
    const message = err instanceof Error ? err.message : String(err);
    if (message.includes("Cannot find module") || message.includes("MODULE_NOT_FOUND")) {
      throw new Error(
        "better-sqlite3 is required for SQLite storage. Install it: npm install better-sqlite3"
      );
    }
    throw err;
  }
}

export { SQLiteProviderStore, SQLiteSessionStore, SQLiteTokenStore, createSQLiteStorage };
//# sourceMappingURL=sqlite.js.map
//# sourceMappingURL=sqlite.js.map