'use strict';

var chunkJH25NWL4_cjs = require('./chunk-JH25NWL4.cjs');
var crypto$1 = require('crypto');

// src/storage/domains/skills/base.ts
var SkillsStorage = class extends chunkJH25NWL4_cjs.VersionedStorageDomain {
  listKey = "skills";
  versionMetadataFields = [
    "id",
    "skillId",
    "versionNumber",
    "changedFields",
    "changeMessage",
    "createdAt"
  ];
  constructor() {
    super({
      component: "STORAGE",
      name: "SKILLS"
    });
  }
};
var InMemorySkillsStorage = class extends SkillsStorage {
  db;
  constructor({ db }) {
    super();
    this.db = db;
  }
  async dangerouslyClearAll() {
    this.db.skills.clear();
    this.db.skillVersions.clear();
  }
  // ==========================================================================
  // Skill CRUD Methods
  // ==========================================================================
  async getById(id) {
    const config = this.db.skills.get(id);
    return config ? this.deepCopyConfig(config) : null;
  }
  async create(input) {
    const { skill } = input;
    if (this.db.skills.has(skill.id)) {
      throw new Error(`Skill with id ${skill.id} already exists`);
    }
    const now = /* @__PURE__ */ new Date();
    const newConfig = {
      id: skill.id,
      status: "draft",
      activeVersionId: void 0,
      authorId: skill.authorId,
      createdAt: now,
      updatedAt: now
    };
    this.db.skills.set(skill.id, newConfig);
    const { id: _id, authorId: _authorId, ...snapshotConfig } = skill;
    const versionId = crypto$1.randomUUID();
    try {
      await this.createVersion({
        id: versionId,
        skillId: skill.id,
        versionNumber: 1,
        ...snapshotConfig,
        changedFields: Object.keys(snapshotConfig),
        changeMessage: "Initial version"
      });
    } catch (error) {
      this.db.skills.delete(skill.id);
      throw error;
    }
    return this.deepCopyConfig(newConfig);
  }
  async update(input) {
    const { id, ...updates } = input;
    const existingConfig = this.db.skills.get(id);
    if (!existingConfig) {
      throw new Error(`Skill with id ${id} not found`);
    }
    const { authorId, activeVersionId, status, ...configFields } = updates;
    const configFieldNames = [
      "name",
      "description",
      "instructions",
      "license",
      "compatibility",
      "source",
      "references",
      "scripts",
      "assets",
      "metadata",
      "tree"
    ];
    const hasConfigUpdate = configFieldNames.some((field) => field in configFields);
    const updatedConfig = {
      ...existingConfig,
      ...authorId !== void 0 && { authorId },
      ...activeVersionId !== void 0 && { activeVersionId },
      ...status !== void 0 && { status },
      updatedAt: /* @__PURE__ */ new Date()
    };
    if (activeVersionId !== void 0 && status === void 0) {
      updatedConfig.status = "published";
    }
    if (hasConfigUpdate) {
      const latestVersion = await this.getLatestVersion(id);
      if (!latestVersion) {
        throw new Error(`No versions found for skill ${id}`);
      }
      const {
        id: _versionId,
        skillId: _skillId,
        versionNumber: _versionNumber,
        changedFields: _changedFields,
        changeMessage: _changeMessage,
        createdAt: _createdAt,
        ...latestConfig
      } = latestVersion;
      const newConfig = {
        ...latestConfig,
        ...configFields
      };
      const changedFields = configFieldNames.filter(
        (field) => field in configFields && JSON.stringify(configFields[field]) !== JSON.stringify(latestConfig[field])
      );
      if (changedFields.length > 0) {
        const newVersionId = crypto$1.randomUUID();
        const newVersionNumber = latestVersion.versionNumber + 1;
        await this.createVersion({
          id: newVersionId,
          skillId: id,
          versionNumber: newVersionNumber,
          ...newConfig,
          changedFields,
          changeMessage: `Updated ${changedFields.join(", ")}`
        });
      }
    }
    this.db.skills.set(id, updatedConfig);
    return this.deepCopyConfig(updatedConfig);
  }
  async delete(id) {
    this.db.skills.delete(id);
    await this.deleteVersionsByParentId(id);
  }
  async list(args) {
    const { page = 0, perPage: perPageInput, orderBy, authorId, metadata } = args || {};
    const { field, direction } = this.parseOrderBy(orderBy);
    const perPage = chunkJH25NWL4_cjs.normalizePerPage(perPageInput, 100);
    if (page < 0) {
      throw new Error("page must be >= 0");
    }
    const maxOffset = Number.MAX_SAFE_INTEGER / 2;
    if (page * perPage > maxOffset) {
      throw new Error("page value too large");
    }
    let configs = Array.from(this.db.skills.values());
    if (authorId !== void 0) {
      configs = configs.filter((config) => config.authorId === authorId);
    }
    if (metadata && Object.keys(metadata).length > 0) {
      configs = configs.filter((_config) => {
        return false;
      });
    }
    const sortedConfigs = this.sortConfigs(configs, field, direction);
    const clonedConfigs = sortedConfigs.map((config) => this.deepCopyConfig(config));
    const { offset, perPage: perPageForResponse } = chunkJH25NWL4_cjs.calculatePagination(page, perPageInput, perPage);
    return {
      skills: clonedConfigs.slice(offset, offset + perPage),
      total: clonedConfigs.length,
      page,
      perPage: perPageForResponse,
      hasMore: offset + perPage < clonedConfigs.length
    };
  }
  // ==========================================================================
  // Skill Version Methods
  // ==========================================================================
  async createVersion(input) {
    if (this.db.skillVersions.has(input.id)) {
      throw new Error(`Version with id ${input.id} already exists`);
    }
    for (const version2 of this.db.skillVersions.values()) {
      if (version2.skillId === input.skillId && version2.versionNumber === input.versionNumber) {
        throw new Error(`Version number ${input.versionNumber} already exists for skill ${input.skillId}`);
      }
    }
    const version = {
      ...input,
      createdAt: /* @__PURE__ */ new Date()
    };
    this.db.skillVersions.set(input.id, this.deepCopyVersion(version));
    return this.deepCopyVersion(version);
  }
  async getVersion(id) {
    const version = this.db.skillVersions.get(id);
    return version ? this.deepCopyVersion(version) : null;
  }
  async getVersionByNumber(skillId, versionNumber) {
    for (const version of this.db.skillVersions.values()) {
      if (version.skillId === skillId && version.versionNumber === versionNumber) {
        return this.deepCopyVersion(version);
      }
    }
    return null;
  }
  async getLatestVersion(skillId) {
    let latest = null;
    for (const version of this.db.skillVersions.values()) {
      if (version.skillId === skillId) {
        if (!latest || version.versionNumber > latest.versionNumber) {
          latest = version;
        }
      }
    }
    return latest ? this.deepCopyVersion(latest) : null;
  }
  async listVersions(input) {
    const { skillId, page = 0, perPage: perPageInput, orderBy } = input;
    const { field, direction } = this.parseVersionOrderBy(orderBy);
    const perPage = chunkJH25NWL4_cjs.normalizePerPage(perPageInput, 20);
    if (page < 0) {
      throw new Error("page must be >= 0");
    }
    const maxOffset = Number.MAX_SAFE_INTEGER / 2;
    if (page * perPage > maxOffset) {
      throw new Error("page value too large");
    }
    let versions = Array.from(this.db.skillVersions.values()).filter((v) => v.skillId === skillId);
    versions = this.sortVersions(versions, field, direction);
    const clonedVersions = versions.map((v) => this.deepCopyVersion(v));
    const total = clonedVersions.length;
    const { offset, perPage: perPageForResponse } = chunkJH25NWL4_cjs.calculatePagination(page, perPageInput, perPage);
    const paginatedVersions = clonedVersions.slice(offset, offset + perPage);
    return {
      versions: paginatedVersions,
      total,
      page,
      perPage: perPageForResponse,
      hasMore: offset + perPage < total
    };
  }
  async deleteVersion(id) {
    this.db.skillVersions.delete(id);
  }
  async deleteVersionsByParentId(entityId) {
    const idsToDelete = [];
    for (const [id, version] of this.db.skillVersions.entries()) {
      if (version.skillId === entityId) {
        idsToDelete.push(id);
      }
    }
    for (const id of idsToDelete) {
      this.db.skillVersions.delete(id);
    }
  }
  async countVersions(skillId) {
    let count = 0;
    for (const version of this.db.skillVersions.values()) {
      if (version.skillId === skillId) {
        count++;
      }
    }
    return count;
  }
  // ==========================================================================
  // Private Helper Methods
  // ==========================================================================
  deepCopyConfig(config) {
    return {
      ...config
    };
  }
  deepCopyVersion(version) {
    return structuredClone(version);
  }
  sortConfigs(configs, field, direction) {
    return configs.sort((a, b) => {
      const aValue = a[field].getTime();
      const bValue = b[field].getTime();
      return direction === "ASC" ? aValue - bValue : bValue - aValue;
    });
  }
  sortVersions(versions, field, direction) {
    return versions.sort((a, b) => {
      let aVal;
      let bVal;
      if (field === "createdAt") {
        aVal = a.createdAt.getTime();
        bVal = b.createdAt.getTime();
      } else {
        aVal = a.versionNumber;
        bVal = b.versionNumber;
      }
      return direction === "ASC" ? aVal - bVal : bVal - aVal;
    });
  }
};

// src/storage/domains/skills/filesystem.ts
var FilesystemSkillsStorage = class extends SkillsStorage {
  helpers;
  constructor({ db }) {
    super();
    this.helpers = new chunkJH25NWL4_cjs.FilesystemVersionedHelpers({
      db,
      entitiesFile: "skills.json",
      parentIdField: "skillId",
      name: "FilesystemSkillsStorage",
      versionMetadataFields: ["id", "skillId", "versionNumber", "changedFields", "changeMessage", "createdAt"]
    });
  }
  async init() {
    await this.helpers.db.init();
  }
  async dangerouslyClearAll() {
    await this.helpers.dangerouslyClearAll();
  }
  async getById(id) {
    return this.helpers.getById(id);
  }
  async create(input) {
    const { skill } = input;
    const now = /* @__PURE__ */ new Date();
    const entity = {
      id: skill.id,
      status: "draft",
      activeVersionId: void 0,
      authorId: skill.authorId,
      createdAt: now,
      updatedAt: now
    };
    await this.helpers.createEntity(skill.id, entity);
    const { id: _id, authorId: _authorId, ...snapshotConfig } = skill;
    const versionId = crypto.randomUUID();
    await this.createVersion({
      id: versionId,
      skillId: skill.id,
      versionNumber: 1,
      ...snapshotConfig,
      changedFields: Object.keys(snapshotConfig),
      changeMessage: "Initial version"
    });
    return structuredClone(entity);
  }
  async update(input) {
    const { id, ...updates } = input;
    const existing = await this.helpers.getById(id);
    if (!existing) {
      throw new Error(`FilesystemSkillsStorage: skill with id ${id} not found`);
    }
    const { authorId, activeVersionId, status, ...configFields } = updates;
    const configFieldNames = [
      "name",
      "description",
      "instructions",
      "license",
      "compatibility",
      "source",
      "references",
      "scripts",
      "assets",
      "metadata",
      "tree"
    ];
    const hasConfigUpdate = configFieldNames.some((field) => field in configFields);
    if (hasConfigUpdate) {
      const latestVersion = await this.getLatestVersion(id);
      if (!latestVersion) {
        throw new Error(`No versions found for skill ${id}`);
      }
      const {
        id: _versionId,
        skillId: _skillId,
        versionNumber: _versionNumber,
        changedFields: _changedFields,
        changeMessage: _changeMessage,
        createdAt: _createdAt,
        ...latestConfig
      } = latestVersion;
      const newConfig = {
        ...latestConfig,
        ...configFields
      };
      const changedFields = configFieldNames.filter(
        (field) => field in configFields && JSON.stringify(configFields[field]) !== JSON.stringify(latestConfig[field])
      );
      if (changedFields.length > 0) {
        const newVersionId = crypto.randomUUID();
        const newVersionNumber = latestVersion.versionNumber + 1;
        await this.createVersion({
          id: newVersionId,
          skillId: id,
          versionNumber: newVersionNumber,
          ...newConfig,
          changedFields,
          changeMessage: `Updated ${changedFields.join(", ")}`
        });
      }
    }
    const entityUpdates = {
      ...authorId !== void 0 && { authorId },
      ...activeVersionId !== void 0 && { activeVersionId },
      ...status !== void 0 && { status }
    };
    if (activeVersionId !== void 0 && status === void 0) {
      entityUpdates.status = "published";
    }
    return await this.helpers.updateEntity(id, entityUpdates);
  }
  async delete(id) {
    await this.helpers.deleteEntity(id);
  }
  async list(args) {
    const { page, perPage, orderBy, authorId, metadata } = args || {};
    const result = await this.helpers.listEntities({
      page,
      perPage,
      orderBy,
      listKey: "skills",
      filters: { authorId, metadata }
    });
    return result;
  }
  async createVersion(input) {
    return this.helpers.createVersion(input);
  }
  async getVersion(id) {
    return this.helpers.getVersion(id);
  }
  async getVersionByNumber(skillId, versionNumber) {
    return this.helpers.getVersionByNumber(skillId, versionNumber);
  }
  async getLatestVersion(skillId) {
    return this.helpers.getLatestVersion(skillId);
  }
  async listVersions(input) {
    const result = await this.helpers.listVersions(input, "skillId");
    return result;
  }
  async deleteVersion(id) {
    await this.helpers.deleteVersion(id);
  }
  async deleteVersionsByParentId(entityId) {
    await this.helpers.deleteVersionsByParentId(entityId);
  }
  async countVersions(skillId) {
    return this.helpers.countVersions(skillId);
  }
};

exports.FilesystemSkillsStorage = FilesystemSkillsStorage;
exports.InMemorySkillsStorage = InMemorySkillsStorage;
exports.SkillsStorage = SkillsStorage;
//# sourceMappingURL=chunk-FAK3QHAY.cjs.map
//# sourceMappingURL=chunk-FAK3QHAY.cjs.map