import { makeOrbitalWithUses, makePageRef, makeTraitRef } from '@almadar/core/builders';

// factory-runtime/extract-manifest.ts
var STATIC_PARAM_FIELDS = [
  {
    name: "fields",
    type: "EntityField[]",
    description: "Extra fields appended to the canonical entity."
  },
  {
    name: "pagePath",
    type: "string",
    description: "URL override for the orbital first page."
  },
  {
    name: "persistence",
    type: "'persistent' | 'runtime' | 'singleton' | 'instance' | 'local'",
    description: "Override the canonical entity persistence mode."
  },
  {
    name: "entityName",
    type: "string",
    description: "Rename the canonical entity. PascalCase singular, \u226432 chars. Threads through every trait's linkedEntity binding; compiler rewrites @Entity.x refs."
  },
  {
    name: "collection",
    type: "string",
    description: "Override derived collection key. Defaults to plural(entityName).toLowerCase()."
  },
  {
    name: "traitOverrides",
    type: "Partial<Record<TraitName, { config?, linkedEntity?, events?, name?, emitsScope?, listens? }>>",
    description: ".lolo's native trait-composition surface 1:1: per-imported-trait config, linkedEntity, events, name, emitsScope, listens. effects is excluded (atom-owned; use listens via a sibling trait)."
  }
];
function splitTraits(traits) {
  const refTraitNames = [];
  const inlineTraitNames = [];
  for (const t of traits) {
    if (!t || typeof t !== "object") continue;
    const tName = typeof t.name === "string" ? t.name : null;
    if (!tName) continue;
    if (typeof t.ref === "string") {
      refTraitNames.push(tName);
    } else {
      inlineTraitNames.push(tName);
    }
  }
  return { refTraitNames, inlineTraitNames };
}
function extractManifest(orb) {
  const behaviorName = orb.name;
  return orb.orbitals.map((orbital) => {
    const { refTraitNames, inlineTraitNames } = splitTraits(orbital.traits);
    return {
      organism: behaviorName,
      orbitalName: orbital.name,
      paramFields: STATIC_PARAM_FIELDS,
      traitNames: refTraitNames,
      inlineTraitNames
    };
  });
}
function validateOrbitalFactoryParams(manifest, raw) {
  if (raw === null || Array.isArray(raw)) {
    return {
      ok: false,
      error: { kind: "not-object", received: Array.isArray(raw) ? "array" : "null" }
    };
  }
  const ALLOWED_KEYS = /* @__PURE__ */ new Set([
    "fields",
    "pagePath",
    "persistence",
    "entityName",
    "collection",
    "traitOverrides"
  ]);
  for (const key of Object.keys(raw)) {
    if (!ALLOWED_KEYS.has(key)) {
      return { ok: false, error: { kind: "unknown-key", key } };
    }
  }
  const candidate = raw;
  if (candidate.traitOverrides !== void 0) {
    const to = candidate.traitOverrides;
    if (to === null || typeof to !== "object" || Array.isArray(to)) {
      return {
        ok: false,
        error: {
          kind: "trait-overrides-not-object",
          received: Array.isArray(to) ? "array" : typeof to
        }
      };
    }
    const allowed = new Set(manifest.traitNames);
    for (const traitName of Object.keys(to)) {
      if (!allowed.has(traitName)) {
        return {
          ok: false,
          error: {
            kind: "unknown-trait-override",
            trait: traitName,
            allowed: manifest.traitNames
          }
        };
      }
    }
  }
  return { ok: true, params: candidate };
}
function assertResolvedEntity(entity, orbitalName, orbName) {
  if (typeof entity === "string") {
    throw new Error(
      `applyParamsToOrb: orbital "${orbitalName}" in orb "${orbName}" has an unresolved entity reference (string form). Pass a resolved .orb.`
    );
  }
  if ("extends" in entity) {
    throw new Error(
      `applyParamsToOrb: orbital "${orbitalName}" in orb "${orbName}" has an unresolved EntityCall ("extends" form). Pass a resolved .orb.`
    );
  }
  return entity;
}
function findOrbitalOrThrow(orb, orbitalName) {
  const orbital = orb.orbitals.find((o) => o.name === orbitalName);
  if (!orbital) {
    throw new Error(
      `applyParamsToOrb: orbital "${orbitalName}" not found in orb "${orb.name}". Available: ${orb.orbitals.map((o) => o.name).join(", ")}`
    );
  }
  return orbital;
}
function buildEntity(ctx, effectiveName, effectiveCollection, params) {
  const canonicalFields = Array.isArray(ctx.canonicalEntity.fields) ? ctx.canonicalEntity.fields : [];
  const extras = params.fields ?? [];
  for (const f of extras) {
    if (f.type === "enum") {
      if (!Array.isArray(f.values) || f.values.length === 0) {
        throw new Error(
          `Field "${f.name ?? "<unnamed>"}" (type: "enum") requires a non-empty \`values: string[]\` array. Got: ${f.values === void 0 ? "undefined" : JSON.stringify(f.values)}.`
        );
      }
    }
    if (f.type === "relation") {
      const rel = f.relation;
      if (!rel || typeof rel.entity !== "string" || rel.entity.length === 0) {
        throw new Error(
          `Field "${f.name ?? "<unnamed>"}" (type: "relation") requires \`relation: { entity: <EntityName>, cardinality: "one" | "many" }\`. Got: ${rel === void 0 ? "undefined" : JSON.stringify(rel)}.`
        );
      }
      if (rel.cardinality !== "one" && rel.cardinality !== "many") {
        throw new Error(
          `Field "${f.name ?? "<unnamed>"}" (type: "relation") requires \`relation.cardinality: "one" | "many"\`. Got: ${rel.cardinality === void 0 ? "undefined" : JSON.stringify(rel.cardinality)}.`
        );
      }
    }
  }
  let mergedFields;
  if (extras.length === 0) {
    mergedFields = canonicalFields;
  } else {
    const extraNames = new Set(extras.map((f) => f.name));
    mergedFields = [
      ...canonicalFields.filter((f) => !extraNames.has(f.name)),
      ...extras
    ];
  }
  const entity = {
    name: effectiveName,
    persistence: params.persistence ?? ctx.canonicalEntity.persistence,
    fields: [...mergedFields]
  };
  if (effectiveCollection !== void 0) {
    entity.collection = effectiveCollection;
  }
  return entity;
}
function isTraitReferenceObject(t) {
  if (t === null || typeof t !== "object") return false;
  if (!("ref" in t)) return false;
  return typeof t.ref === "string";
}
function isPageRefObject(p) {
  if (p === null || typeof p !== "object") return false;
  if (!("ref" in p)) return false;
  return typeof p.ref === "string";
}
function rewriteInlineLinkedEntity(shape, oldName, newName) {
  if (shape.linkedEntity !== oldName) return shape;
  return { ...shape, linkedEntity: newName };
}
var ENTITY_POSITIONAL_OPS = [
  { op: "fetch", entityIndex: 1 },
  { op: "ref", entityIndex: 1 },
  { op: "spawn", entityIndex: 1 },
  { op: "persist", actionGuard: /* @__PURE__ */ new Set(["create", "update", "delete"]), entityIndex: 2 }
];
var ENTITY_VALUED_PROPS = /* @__PURE__ */ new Set([
  "entity",
  "source",
  "entityType",
  "linkedEntity"
]);
function rewriteEntityInSExpr(value, oldName, newName) {
  if (value === null) return null;
  if (typeof value === "boolean" || typeof value === "number") return value;
  if (typeof value === "string") {
    const prefix = `@${oldName}`;
    if (value === prefix || value.startsWith(`${prefix}.`)) {
      return `@${newName}${value.slice(prefix.length)}`;
    }
    return value;
  }
  if (Array.isArray(value)) {
    const first = value[0];
    if (typeof first === "string") {
      for (const entry of ENTITY_POSITIONAL_OPS) {
        if (first !== entry.op) continue;
        if (entry.actionGuard !== void 0) {
          const action = value[1];
          if (typeof action !== "string" || !entry.actionGuard.has(action)) continue;
        }
        const at = entry.entityIndex;
        const slot = value[at];
        if (typeof slot !== "string" || slot !== oldName) continue;
        const rewritten = [];
        for (let i = 0; i < value.length; i++) {
          rewritten.push(i === at ? newName : rewriteEntityInSExpr(value[i], oldName, newName));
        }
        return rewritten;
      }
    }
    return value.map((v) => rewriteEntityInSExpr(v, oldName, newName));
  }
  return rewriteEntityInSExprMap(value, oldName, newName);
}
function rewriteEntityInSExprMap(obj, oldName, newName) {
  const next = {};
  for (const [k, v] of Object.entries(obj)) {
    if (ENTITY_VALUED_PROPS.has(k) && typeof v === "string" && v === oldName) {
      next[k] = newName;
    } else {
      next[k] = rewriteEntityInSExpr(v, oldName, newName);
    }
  }
  return next;
}
function rewritePayloadFieldType(typeStr, oldName, newName) {
  if (typeStr === oldName) return newName;
  if (typeStr === `[${oldName}]`) return `[${newName}]`;
  return typeStr;
}
function rewriteEventContract(contract, oldName, newName) {
  if (!contract.payloadSchema || contract.payloadSchema.length === 0) return contract;
  return {
    ...contract,
    payloadSchema: contract.payloadSchema.map((f) => {
      const next = { ...f, type: rewritePayloadFieldType(f.type, oldName, newName) };
      if (typeof f.entityType === "string" && f.entityType === oldName) {
        next.entityType = newName;
      }
      return next;
    })
  };
}
function rewriteListener(listener, oldName, newName) {
  if (!listener.payloadMapping) return listener;
  const prefix = `@${oldName}`;
  const nextMapping = {};
  for (const [k, v] of Object.entries(listener.payloadMapping)) {
    nextMapping[k] = v === prefix || v.startsWith(`${prefix}.`) ? `@${newName}${v.slice(prefix.length)}` : v;
  }
  return { ...listener, payloadMapping: nextMapping };
}
function rewriteTick(tick, oldName, newName) {
  const next = { ...tick };
  if (next.guard !== void 0 && next.guard !== null) {
    next.guard = rewriteEntityInSExpr(next.guard, oldName, newName);
  }
  next.effects = next.effects.map(
    (e) => rewriteEntityInSExpr(e, oldName, newName)
  );
  return next;
}
function rebindInlineTraitEntity(trait, oldName, newName) {
  if (oldName === newName) return trait;
  return rewriteEntityInInlineTrait(rewriteInlineLinkedEntity(trait, oldName, newName), oldName, newName);
}
function rewriteEntityInInlineTrait(trait, oldName, newName) {
  if (oldName === newName) return trait;
  const next = { ...trait };
  if (next.stateMachine) {
    next.stateMachine = {
      ...next.stateMachine,
      transitions: next.stateMachine.transitions.map((t) => {
        const updated = { ...t };
        if (updated.guard !== void 0 && updated.guard !== null) {
          updated.guard = rewriteEntityInSExpr(updated.guard, oldName, newName);
        }
        if (updated.effects) {
          updated.effects = updated.effects.map(
            (e) => rewriteEntityInSExpr(e, oldName, newName)
          );
        }
        return updated;
      })
    };
  }
  if (next.initialEffects) {
    next.initialEffects = next.initialEffects.map(
      (e) => rewriteEntityInSExpr(e, oldName, newName)
    );
  }
  if (next.ticks) {
    next.ticks = next.ticks.map((t) => rewriteTick(t, oldName, newName));
  }
  if (next.emits) {
    next.emits = next.emits.map((c) => rewriteEventContract(c, oldName, newName));
  }
  if (next.listens) {
    next.listens = next.listens.map((l) => rewriteListener(l, oldName, newName));
  }
  return next;
}
function rebuildTraits(ctx, effectiveEntityName, traits) {
  return traits.map((t) => {
    if (!isTraitReferenceObject(t)) {
      if (typeof t === "string") return t;
      return rebindInlineTraitEntity(t, ctx.canonicalEntityName, effectiveEntityName);
    }
    const rewrittenLinkedEntity = t.linkedEntity === ctx.canonicalEntityName ? effectiveEntityName : t.linkedEntity;
    const opts = {
      ...t,
      linkedEntity: rewrittenLinkedEntity
    };
    return makeTraitRef(opts);
  });
}
function rebuildPages(ctx, effectiveEntityName, pages) {
  if (!pages) return [];
  return pages.map((p) => {
    if (!isPageRefObject(p)) {
      return p;
    }
    const rewrittenLinkedEntity = p.linkedEntity === ctx.canonicalEntityName ? effectiveEntityName : p.linkedEntity;
    const opts = {
      ...p,
      linkedEntity: rewrittenLinkedEntity
    };
    return makePageRef(opts);
  });
}
function applyParamsToOrb(orb, orbitalName, _manifest, params) {
  const orbital = findOrbitalOrThrow(orb, orbitalName);
  const canonicalEntity = assertResolvedEntity(orbital.entity, orbitalName, orb.name);
  const canonicalEntityName = canonicalEntity.name;
  const effectiveEntityName = params.entityName ?? canonicalEntityName;
  const effectiveCollection = typeof canonicalEntity.collection === "string" ? params.collection ?? (params.entityName ? `${params.entityName.toLowerCase()}s` : canonicalEntity.collection) : params.collection;
  const ctx = { canonicalEntityName, canonicalEntity };
  const built = makeOrbitalWithUses({
    name: orbital.name,
    uses: orbital.uses ?? [],
    entity: buildEntity(ctx, effectiveEntityName, effectiveCollection, params),
    traits: rebuildTraits(ctx, effectiveEntityName, orbital.traits),
    pages: rebuildPages(ctx, effectiveEntityName, orbital.pages)
  });
  if (built.traits && params.traitOverrides !== void 0) {
    built.traits = built.traits.map((t) => {
      if (!isTraitReferenceObject(t) || typeof t.name !== "string") return t;
      const override = params.traitOverrides?.[t.name];
      if (!override) return t;
      const merged = { ...t };
      if (override.config !== void 0) {
        merged.config = { ...t.config ?? {}, ...override.config };
      }
      if (override.linkedEntity !== void 0) merged.linkedEntity = override.linkedEntity;
      if (override.events !== void 0) {
        if (override.events === null || typeof override.events !== "object" || Array.isArray(override.events)) {
          throw new Error(
            `traitOverrides["${t.name}"].events must be a Record<string,string> (rename map like { "OPEN": "ADD_ITEM" }), got ${Array.isArray(override.events) ? "an array" : typeof override.events}`
          );
        }
        for (const [k, v] of Object.entries(override.events)) {
          if (typeof v !== "string") {
            throw new Error(
              `traitOverrides["${t.name}"].events["${k}"] must be a string (target event name), got ${typeof v}`
            );
          }
        }
        merged.events = { ...t.events ?? {}, ...override.events };
      }
      if (override.name !== void 0) merged.name = override.name;
      if (override.emitsScope !== void 0) merged.emitsScope = override.emitsScope;
      if (override.listens !== void 0) merged.listens = override.listens;
      return merged;
    });
  }
  if (built.pages && params.pagePath !== void 0) {
    built.pages = built.pages.map((p, idx) => {
      if (!isPageRefObject(p) || idx !== 0) return p;
      return { ...p, path: params.pagePath };
    });
  }
  return built;
}

// factory-runtime/apply-params-to-whole-orb.ts
function applyParamsToWholeOrb(orb, manifests, params) {
  const manifestByOrbital = /* @__PURE__ */ new Map();
  for (const m of manifests) {
    manifestByOrbital.set(m.orbitalName, m);
  }
  const rebuilt = [];
  for (const orbital of orb.orbitals) {
    const manifest = manifestByOrbital.get(orbital.name);
    if (!manifest) {
      rebuilt.push(orbital);
      continue;
    }
    rebuilt.push(applyParamsToOrb(orb, orbital.name, manifest, params));
  }
  return { ...orb, orbitals: rebuilt };
}

export { applyParamsToOrb, applyParamsToWholeOrb, extractManifest, rebindInlineTraitEntity, validateOrbitalFactoryParams };
//# sourceMappingURL=index.js.map
//# sourceMappingURL=index.js.map