"use strict";
var __create = Object.create;
var __defProp = Object.defineProperty;
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __getProtoOf = Object.getPrototypeOf;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __export = (target, all) => {
  for (var name in all)
    __defProp(target, name, { get: all[name], enumerable: true });
};
var __copyProps = (to, from, except, desc) => {
  if (from && typeof from === "object" || typeof from === "function") {
    for (let key of __getOwnPropNames(from))
      if (!__hasOwnProp.call(to, key) && key !== except)
        __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
  }
  return to;
};
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
  // If the importer is in node compatibility mode or this is not an ESM
  // file that has been converted to a CommonJS file using a Babel-
  // compatible transform (i.e. "__esModule" has not been set), then set
  // "default" to the CommonJS "module.exports" for node compatibility.
  isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
  mod
));
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);

// src/builtins/sqlite-storage/sqlite-settings.addon.ts
var sqlite_settings_addon_exports = {};
__export(sqlite_settings_addon_exports, {
  SqliteSettingsAddon: () => SqliteSettingsAddon,
  default: () => sqlite_settings_addon_default
});
module.exports = __toCommonJS(sqlite_settings_addon_exports);

// src/builtins/sqlite-storage/sqlite-settings-backend.ts
var import_better_sqlite3 = __toESM(require("better-sqlite3"));
var import_node_crypto = require("crypto");
var SqliteSettingsBackend = class {
  constructor(dbPath, runtimeDefaults) {
    this.dbPath = dbPath;
    this.runtimeDefaults = runtimeDefaults ?? {};
  }
  db = null;
  ensuredTables = /* @__PURE__ */ new Set();
  runtimeDefaults;
  async initialize() {
    const dir = this.dbPath.substring(0, this.dbPath.lastIndexOf("/"));
    if (dir) {
      const fs = await import("fs");
      fs.mkdirSync(dir, { recursive: true });
    }
    this.db = new import_better_sqlite3.default(this.dbPath);
    this.db.pragma("journal_mode = WAL");
    this.db.pragma("foreign_keys = ON");
    const isEmpty = await this.isEmpty("system-settings");
    if (isEmpty) {
      await this.seedDefaults();
    }
  }
  async shutdown() {
    this.db?.close();
    this.db = null;
  }
  // ---------------------------------------------------------------------------
  // ISettingsBackend implementation
  // ---------------------------------------------------------------------------
  async get(collection, key) {
    this.ensureTable(collection);
    const row = this.getDb().prepare(`SELECT data FROM "${collection}" WHERE id = ?`).get(key);
    if (!row) return void 0;
    return JSON.parse(row.data);
  }
  async set(collection, key, value) {
    this.ensureTable(collection);
    this.getDb().prepare(`INSERT INTO "${collection}" (id, data) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data`).run(key, JSON.stringify(value));
  }
  async query(collection, filter) {
    this.ensureTable(collection);
    let sql = `SELECT id, data FROM "${collection}"`;
    const params = [];
    const whereClauses = [];
    if (filter?.where) {
      for (const [field, value] of Object.entries(filter.where)) {
        if (field === "id") {
          whereClauses.push("id = ?");
          params.push(value);
        } else {
          whereClauses.push(`json_extract(data, '$.${field}') = ?`);
          params.push(typeof value === "object" ? JSON.stringify(value) : value);
        }
      }
    }
    if (filter?.whereIn) {
      for (const [field, values] of Object.entries(filter.whereIn)) {
        const placeholders = values.map(() => "?").join(", ");
        if (field === "id") {
          whereClauses.push(`id IN (${placeholders})`);
        } else {
          whereClauses.push(`json_extract(data, '$.${field}') IN (${placeholders})`);
        }
        params.push(...values);
      }
    }
    if (filter?.whereBetween) {
      for (const [field, [low, high]] of Object.entries(filter.whereBetween)) {
        if (field === "id") {
          whereClauses.push("id BETWEEN ? AND ?");
        } else {
          whereClauses.push(`json_extract(data, '$.${field}') BETWEEN ? AND ?`);
        }
        params.push(low, high);
      }
    }
    if (whereClauses.length > 0) {
      sql += ` WHERE ${whereClauses.join(" AND ")}`;
    }
    if (filter?.orderBy) {
      const dir = filter.orderBy.direction === "desc" ? "DESC" : "ASC";
      if (filter.orderBy.field === "id") {
        sql += ` ORDER BY id ${dir}`;
      } else {
        sql += ` ORDER BY json_extract(data, '$.${filter.orderBy.field}') ${dir}`;
      }
    }
    if (filter?.limit) {
      sql += ` LIMIT ?`;
      params.push(filter.limit);
    }
    if (filter?.offset) {
      sql += ` OFFSET ?`;
      params.push(filter.offset);
    }
    const rows = this.getDb().prepare(sql).all(...params);
    return rows.map((row) => ({
      id: row.id,
      data: JSON.parse(row.data)
    }));
  }
  async insert(collection, record) {
    this.ensureTable(collection);
    const id = record.id || (0, import_node_crypto.randomUUID)();
    this.getDb().prepare(`INSERT INTO "${collection}" (id, data) VALUES (?, ?)`).run(id, JSON.stringify(record.data));
  }
  async update(collection, id, data) {
    this.ensureTable(collection);
    this.getDb().prepare(`UPDATE "${collection}" SET data = ? WHERE id = ?`).run(JSON.stringify(data), id);
  }
  async delete(collection, key) {
    this.ensureTable(collection);
    this.getDb().prepare(`DELETE FROM "${collection}" WHERE id = ?`).run(key);
  }
  async count(collection, filter) {
    this.ensureTable(collection);
    if (!filter) {
      const row = this.getDb().prepare(`SELECT COUNT(*) AS cnt FROM "${collection}"`).get();
      return row?.cnt ?? 0;
    }
    const rows = await this.query(collection, { ...filter, limit: void 0, offset: void 0 });
    return rows.length;
  }
  async isEmpty(collection) {
    this.ensureTable(collection);
    const row = this.getDb().prepare(`SELECT COUNT(*) AS cnt FROM "${collection}"`).get();
    return (row?.cnt ?? 0) === 0;
  }
  // ---------------------------------------------------------------------------
  // Legacy SettingsStore compatibility (used by ConfigManager.setSettingsStore)
  // ---------------------------------------------------------------------------
  /** Get a system setting by dot-notation key */
  getSystem(key) {
    this.ensureTable("system-settings");
    const row = this.getDb().prepare('SELECT data FROM "system-settings" WHERE id = ?').get(key);
    if (!row) return void 0;
    return JSON.parse(row.data);
  }
  /** Set a system setting */
  setSystem(key, value) {
    this.ensureTable("system-settings");
    this.getDb().prepare('INSERT INTO "system-settings" (id, data) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data').run(key, JSON.stringify(value));
  }
  /** Get all system settings as flat key-value */
  getAllSystem() {
    this.ensureTable("system-settings");
    const rows = this.getDb().prepare('SELECT id, data FROM "system-settings"').all();
    return Object.fromEntries(rows.map((r) => [r.id, JSON.parse(r.data)]));
  }
  /** Get all settings for an addon */
  getAllAddon(addonId) {
    this.ensureTable("addon-settings");
    const rows = this.getDb().prepare(`SELECT id, data FROM "addon-settings" WHERE json_extract(data, '$.addonId') = ?`).all(addonId);
    if (rows.length === 0) return {};
    const result = {};
    for (const row of rows) {
      const parsed = JSON.parse(row.data);
      const key = row.id.startsWith(`${addonId}.`) ? row.id.slice(addonId.length + 1) : row.id;
      result[key] = parsed.value ?? parsed;
    }
    return result;
  }
  /** Bulk-set all settings for an addon */
  setAllAddon(addonId, config) {
    this.ensureTable("addon-settings");
    const db = this.getDb();
    const deleteStmt = db.prepare(`DELETE FROM "addon-settings" WHERE id LIKE ? || '%'`);
    const insertStmt = db.prepare('INSERT INTO "addon-settings" (id, data) VALUES (?, ?)');
    db.transaction(() => {
      deleteStmt.run(`${addonId}.`);
      for (const [key, value] of Object.entries(config)) {
        insertStmt.run(`${addonId}.${key}`, JSON.stringify({ addonId, key, value }));
      }
    })();
  }
  /** Get all settings for a provider */
  getAllProvider(providerId) {
    return this.getAllScoped("provider-settings", providerId);
  }
  /** Set a provider setting */
  setProvider(providerId, key, value) {
    this.setScopedKey("provider-settings", providerId, key, value);
  }
  /** Get all settings for a device */
  getAllDevice(deviceId) {
    return this.getAllScoped("device-settings", deviceId);
  }
  /** Set a device setting */
  setDevice(deviceId, key, value) {
    this.setScopedKey("device-settings", deviceId, key, value);
  }
  /** Seed system-settings with runtime defaults (first boot) */
  async seedDefaults() {
    this.ensureTable("system-settings");
    const insert = this.getDb().prepare(
      'INSERT OR IGNORE INTO "system-settings" (id, data) VALUES (?, ?)'
    );
    this.getDb().transaction(() => {
      for (const [key, value] of Object.entries(this.runtimeDefaults)) {
        insert.run(key, JSON.stringify(value));
      }
    })();
  }
  // ---------------------------------------------------------------------------
  // Private helpers
  // ---------------------------------------------------------------------------
  getDb() {
    if (!this.db) throw new Error("SqliteSettingsBackend not initialized \u2014 call initialize() first");
    return this.db;
  }
  ensureTable(collection) {
    if (this.ensuredTables.has(collection)) return;
    this.getDb().exec(
      `CREATE TABLE IF NOT EXISTS "${collection}" (id TEXT PRIMARY KEY, data TEXT NOT NULL)`
    );
    this.ensuredTables.add(collection);
  }
  getAllScoped(collection, scopeId) {
    this.ensureTable(collection);
    const rows = this.getDb().prepare(`SELECT id, data FROM "${collection}" WHERE id LIKE ? || '.%'`).all(scopeId);
    const result = {};
    for (const row of rows) {
      const key = row.id.slice(scopeId.length + 1);
      const parsed = JSON.parse(row.data);
      result[key] = parsed.value ?? parsed;
    }
    return result;
  }
  setScopedKey(collection, scopeId, key, value) {
    this.ensureTable(collection);
    this.getDb().prepare(`INSERT INTO "${collection}" (id, data) VALUES (?, ?) ON CONFLICT(id) DO UPDATE SET data = excluded.data`).run(`${scopeId}.${key}`, JSON.stringify({ scopeId, key, value }));
  }
};

// src/builtins/sqlite-storage/sqlite-settings.addon.ts
var SqliteSettingsAddon = class {
  manifest = {
    id: "sqlite-settings",
    name: "SQLite Settings",
    version: "1.0.0",
    capabilities: [{ name: "settings-store", mode: "singleton" }]
  };
  backend = null;
  async initialize(context) {
    const dbPath = context.storageProvider ? context.storageProvider.resolve("addons-data", `${context.id.replace("addon:", "")}/camstack.db`) : context.dataDir ? `${context.dataDir}/camstack.db` : "camstack-data/addons-data/sqlite-settings/camstack.db";
    const runtimeDefaults = context.addonConfig._runtimeDefaults ?? {};
    this.backend = new SqliteSettingsBackend(dbPath, runtimeDefaults);
    await this.backend.initialize();
    context.logger.info(`SQLite settings initialized at ${dbPath}`);
  }
  async shutdown() {
    await this.backend?.shutdown();
  }
  getBackend() {
    return this.backend;
  }
  getCapabilityProvider(name) {
    if (name === "settings-store" && this.backend) {
      return this.backend;
    }
    return null;
  }
  getConfigSchema() {
    return { sections: [] };
  }
  getConfig() {
    return {};
  }
  async onConfigChange(_config) {
  }
};
var sqlite_settings_addon_default = SqliteSettingsAddon;
// Annotate the CommonJS export names for ESM import in node:
0 && (module.exports = {
  SqliteSettingsAddon
});
//# sourceMappingURL=sqlite-settings.addon.js.map