import {
  extractRoleLevel,
  publishMembershipCreated,
  publishRoleAssignmentCreated,
  publishWorkspaceCreated
} from "./chunk-BUAYVN3C.mjs";
import {
  buildMembershipWorkspaceProjectionItem,
  buildRoleAssignmentUserProjectionItem,
  buildRoleAssignmentWorkspaceProjectionItem,
  extractReferenceSlug as extractReferenceSlug2
} from "./chunk-5S6VFBLT.mjs";
import {
  buildMembershipUserProjectionItem,
  extractReferenceSlug
} from "./chunk-I6LUPJUY.mjs";
import {
  executeMultiWrite
} from "./chunk-QJDHVMKT.mjs";
import {
  getDynamoDataService
} from "./chunk-6BB4CRSS.mjs";
import {
  DATA_ENTITY_SK,
  createDataEntityRecord
} from "./chunk-V6AO5T57.mjs";
import {
  ConflictError,
  ValidationError
} from "./chunk-FYHBHHWK.mjs";
import {
  getDynamoControlService
} from "./chunk-EUIP2U5F.mjs";

// src/data/operations/control/membership-constraints/platform-scope-tenant-id.ts
var PLATFORM_SCOPE_TENANT_ID = "platform";

// src/data/operations/control/membership/membership-create-operation.ts
import {
  assertLinkedDataIdentityCardinality,
  extractSummary,
  LinkedDataIdentityCardinalityError
} from "@openhi/types";
import { ulid } from "ulid";

// src/data/operations/control/denormalized-display-names.ts
function extractDenormalizedReferenceDisplay(resource, fieldName) {
  const field = resource[fieldName];
  if (!field || typeof field !== "object") {
    return void 0;
  }
  const display = field.display;
  if (typeof display !== "string") {
    return void 0;
  }
  const trimmed = display.trim();
  return trimmed.length > 0 ? trimmed : void 0;
}

// src/data/operations/control/membership-constraints/assert-workspace-in-tenant-operation.ts
async function assertWorkspaceInTenantOperation(params) {
  const { tenantId, workspaceId, tableName } = params;
  const service = getDynamoControlService(tableName);
  const { data: item } = await service.entities.workspace.get({ tenantId, id: workspaceId, sk: "CURRENT" }).go();
  if (!item) {
    throw new ConflictError(
      `Workspace ${workspaceId} does not belong to tenant ${tenantId}; the workspace must be created in the referenced tenant before this resource can reference it.`,
      { details: { tenantId, workspaceId } }
    );
  }
}

// src/data/operations/control/membership/membership-create-operation.ts
async function createMembershipOperation(params) {
  const { context, body, tableName } = params;
  const service = getDynamoControlService(tableName);
  const id = body.id ?? ulid();
  const parsedResource = typeof body.resource === "string" ? JSON.parse(body.resource) : body.resource ?? {};
  const lastUpdated = context.date ?? (/* @__PURE__ */ new Date()).toISOString();
  const vid = `1`;
  const resource = { resourceType: "Membership", id, ...parsedResource };
  let linkedDataIdentityRef;
  try {
    const ext = assertLinkedDataIdentityCardinality(
      resource
    );
    linkedDataIdentityRef = ext?.valueReference?.reference;
  } catch (e) {
    if (e instanceof LinkedDataIdentityCardinalityError) {
      throw new ValidationError(e.message, { cause: e });
    }
    throw e;
  }
  const resourceRecord = resource;
  const denormalizedTenantName = extractDenormalizedReferenceDisplay(
    resourceRecord,
    "tenant"
  );
  const denormalizedUserName = extractDenormalizedReferenceDisplay(
    resourceRecord,
    "user"
  );
  const denormalizedWorkspaceName = extractDenormalizedReferenceDisplay(
    resourceRecord,
    "workspace"
  );
  const summary = JSON.stringify(extractSummary(resource));
  const userIdFromResource = extractReferenceSlug(resourceRecord, "user");
  const workspaceIdFromResource = extractReferenceSlug(
    resourceRecord,
    "workspace"
  );
  if (workspaceIdFromResource !== void 0) {
    const tenantIdFromResource = extractReferenceSlug(resourceRecord, "tenant");
    const referencedTenantId = tenantIdFromResource ?? context.tenantId;
    await assertWorkspaceInTenantOperation({
      tenantId: referencedTenantId,
      workspaceId: workspaceIdFromResource,
      tableName
    });
  }
  const userProjectionItem = userIdFromResource !== void 0 ? buildMembershipUserProjectionItem({
    tenantId: context.tenantId,
    userId: userIdFromResource,
    workspaceId: workspaceIdFromResource,
    membershipId: id,
    summary,
    vid,
    lastUpdated,
    denormalizedTenantName,
    denormalizedUserName,
    denormalizedWorkspaceName
  }) : void 0;
  const workspaceProjectionItem = userIdFromResource !== void 0 && workspaceIdFromResource !== void 0 ? buildMembershipWorkspaceProjectionItem({
    tenantId: context.tenantId,
    workspaceId: workspaceIdFromResource,
    userId: userIdFromResource,
    membershipId: id,
    summary,
    vid,
    lastUpdated,
    denormalizedUserName
  }) : void 0;
  const canonicalItem = {
    tenantId: context.tenantId,
    id,
    resource: JSON.stringify(resource),
    summary,
    vid,
    lastUpdated,
    linkedDataIdentityRef,
    denormalizedTenantName,
    denormalizedUserName
  };
  const triples = [
    { entity: "membership", action: "put", item: canonicalItem }
  ];
  if (userProjectionItem) {
    triples.push({
      entity: "membershipUserProjection",
      action: "put",
      item: userProjectionItem
    });
  }
  if (workspaceProjectionItem) {
    triples.push({
      entity: "membershipWorkspaceProjection",
      action: "put",
      item: workspaceProjectionItem
    });
  }
  await executeMultiWrite({ service, triples });
  await publishMembershipCreated(context, {
    membershipId: id,
    tenantId: context.tenantId,
    ...userIdFromResource !== void 0 && { userId: userIdFromResource },
    ...workspaceIdFromResource !== void 0 && {
      workspaceId: workspaceIdFromResource
    }
  });
  return {
    id,
    resource,
    meta: { lastUpdated, versionId: vid }
  };
}

// src/data/operations/control/roleassignment/roleassignment-create-operation.ts
import { extractSummary as extractSummary2 } from "@openhi/types";
import { ulid as ulid2 } from "ulid";

// src/data/operations/control/membership-constraints/assert-user-has-tenant-membership-operation.ts
var TENANT_LANE_SK_PREFIX = "MEMBERSHIP#TENANT#";
async function assertUserHasTenantMembershipOperation(params) {
  const { userId, tenantId, tableName } = params;
  if (tenantId === PLATFORM_SCOPE_TENANT_ID) {
    return;
  }
  const service = getDynamoControlService(tableName);
  const result = await service.entities.membershipUserProjection.query.record({ userId }).begins({ sk: TENANT_LANE_SK_PREFIX }).go();
  const matched = (result.data ?? []).some((row) => row.tenantId === tenantId);
  if (!matched) {
    throw new ConflictError(
      `User ${userId} has no tenant-level Membership in tenant ${tenantId}; a Membership must exist before a RoleAssignment can be created.`,
      { details: { userId, tenantId } }
    );
  }
}

// src/data/operations/control/roleassignment/roleassignment-create-operation.ts
async function createRoleAssignmentOperation(params) {
  const { context, body, tableName } = params;
  const service = getDynamoControlService(tableName);
  const id = body.id ?? ulid2();
  const parsedResource = typeof body.resource === "string" ? JSON.parse(body.resource) : body.resource ?? {};
  const lastUpdated = context.date ?? (/* @__PURE__ */ new Date()).toISOString();
  const vid = `1`;
  const resource = { resourceType: "RoleAssignment", id, ...parsedResource };
  const resourceRecord = resource;
  const denormalizedTenantName = extractDenormalizedReferenceDisplay(
    resourceRecord,
    "tenant"
  );
  const denormalizedUserName = extractDenormalizedReferenceDisplay(
    resourceRecord,
    "user"
  );
  const denormalizedRoleName = extractDenormalizedReferenceDisplay(
    resourceRecord,
    "role"
  );
  const summary = JSON.stringify(extractSummary2(resource));
  const userIdFromResource = extractReferenceSlug2(resourceRecord, "user");
  const roleIdFromResource = extractReferenceSlug2(resourceRecord, "role");
  const workspaceIdFromResource = extractReferenceSlug2(
    resourceRecord,
    "workspace"
  );
  if (userIdFromResource !== void 0) {
    const tenantIdFromResource = extractReferenceSlug2(resourceRecord, "tenant");
    const referencedTenantId = tenantIdFromResource ?? context.tenantId;
    await assertUserHasTenantMembershipOperation({
      userId: userIdFromResource,
      tenantId: referencedTenantId,
      tableName
    });
    if (workspaceIdFromResource !== void 0) {
      await assertWorkspaceInTenantOperation({
        tenantId: referencedTenantId,
        workspaceId: workspaceIdFromResource,
        tableName
      });
    }
  }
  const userProjectionItem = userIdFromResource !== void 0 && roleIdFromResource !== void 0 ? buildRoleAssignmentUserProjectionItem({
    tenantId: context.tenantId,
    userId: userIdFromResource,
    workspaceId: workspaceIdFromResource,
    roleId: roleIdFromResource,
    roleAssignmentId: id,
    summary,
    vid,
    lastUpdated,
    denormalizedTenantName,
    denormalizedUserName,
    denormalizedRoleName
  }) : void 0;
  const workspaceProjectionItem = userIdFromResource !== void 0 && roleIdFromResource !== void 0 && workspaceIdFromResource !== void 0 ? buildRoleAssignmentWorkspaceProjectionItem({
    tenantId: context.tenantId,
    workspaceId: workspaceIdFromResource,
    userId: userIdFromResource,
    roleId: roleIdFromResource,
    roleAssignmentId: id,
    summary,
    vid,
    lastUpdated,
    denormalizedUserName,
    denormalizedRoleName
  }) : void 0;
  const canonicalItem = {
    tenantId: context.tenantId,
    id,
    resource: JSON.stringify(resource),
    summary,
    vid,
    lastUpdated,
    denormalizedTenantName,
    denormalizedUserName,
    denormalizedRoleName
  };
  const triples = [
    { entity: "roleAssignment", action: "put", item: canonicalItem }
  ];
  if (userProjectionItem) {
    triples.push({
      entity: "roleAssignmentUserProjection",
      action: "put",
      item: userProjectionItem
    });
  }
  if (workspaceProjectionItem) {
    triples.push({
      entity: "roleAssignmentWorkspaceProjection",
      action: "put",
      item: workspaceProjectionItem
    });
  }
  await executeMultiWrite({ service, triples });
  await publishRoleAssignmentCreated(context, {
    roleAssignmentId: id,
    tenantId: context.tenantId,
    ...userIdFromResource !== void 0 && { userId: userIdFromResource },
    ...workspaceIdFromResource !== void 0 && {
      workspaceId: workspaceIdFromResource
    },
    ...roleIdFromResource !== void 0 && { roleId: roleIdFromResource },
    ...extractRoleLevel(resourceRecord) !== void 0 && {
      roleLevel: extractRoleLevel(resourceRecord)
    }
  });
  return {
    id,
    resource,
    meta: { lastUpdated, versionId: vid }
  };
}

// src/data/operations/control/tenant/tenant-create-operation.ts
import { extractSummary as extractSummary3 } from "@openhi/types";
import { ulid as ulid3 } from "ulid";
async function createTenantOperation(params) {
  const { context, body, tableName } = params;
  const service = getDynamoControlService(tableName);
  const id = body.id ?? ulid3();
  const lastUpdated = context.date;
  const vid = lastUpdated.replace(/[-:T.Z]/g, "").slice(0, 12) || Date.now().toString(36);
  const parsedResource = typeof body.resource === "string" ? JSON.parse(body.resource) : body.resource ?? {};
  const resource = { resourceType: "Tenant", id, ...parsedResource };
  const summary = JSON.stringify(extractSummary3(resource));
  await service.entities.tenant.put({
    tenantId: id,
    id,
    resource: JSON.stringify(resource),
    summary,
    vid,
    lastUpdated
  }).go();
  return { id, resource, meta: { lastUpdated, versionId: vid } };
}

// src/data/operations/control/workspace/workspace-create-operation.ts
import { extractSummary as extractSummary4 } from "@openhi/types";
import { ulid as ulid4 } from "ulid";

// src/data/operations/data/organization/organization-provision-for-workspace-operation.ts
async function provisionOrganizationForWorkspaceOperation(params) {
  const { context, workspaceId, workspaceName, tableName } = params;
  const { tenantId, date } = context;
  const service = getDynamoDataService(tableName);
  const partOf = await resolveTenantOrganizationReference(service, tenantId);
  const resource = {
    resourceType: "Organization",
    id: workspaceId,
    ...workspaceName !== void 0 && workspaceName !== "" ? { name: workspaceName } : {},
    ...partOf !== void 0 ? { partOf } : {},
    meta: {
      lastUpdated: date,
      versionId: "1"
    }
  };
  return createDataEntityRecord(
    service.entities.organization,
    tenantId,
    workspaceId,
    workspaceId,
    resource,
    date
  );
}
async function resolveTenantOrganizationReference(service, tenantId) {
  const result = await service.entities.organization.get({
    tenantId,
    workspaceId: tenantId,
    id: tenantId,
    sk: DATA_ENTITY_SK
  }).go();
  if (result.data === null || result.data === void 0) {
    return void 0;
  }
  return { reference: `Organization/${tenantId}` };
}

// src/data/operations/control/workspace/workspace-create-operation.ts
async function createWorkspaceOperation(params) {
  const { context, body, tableName } = params;
  const { tenantId } = context;
  const service = getDynamoControlService(tableName);
  const id = body.id ?? ulid4();
  const lastUpdated = context.date;
  const vid = lastUpdated.replace(/[-:T.Z]/g, "").slice(0, 12) || Date.now().toString(36);
  const parsedResource = typeof body.resource === "string" ? JSON.parse(body.resource) : body.resource ?? {};
  const resource = { resourceType: "Workspace", id, ...parsedResource };
  const summary = JSON.stringify(extractSummary4(resource));
  await service.entities.workspace.put({
    tenantId,
    id,
    resource: JSON.stringify(resource),
    summary,
    vid,
    lastUpdated
  }).go();
  const workspaceName = typeof parsedResource.name === "string" ? parsedResource.name : void 0;
  await provisionOrganizationForWorkspaceOperation({
    context,
    workspaceId: id,
    workspaceName,
    tableName
  });
  await publishWorkspaceCreated(context, {
    workspaceId: id,
    tenantId
  });
  return { id, resource, meta: { lastUpdated, versionId: vid } };
}

export {
  PLATFORM_SCOPE_TENANT_ID,
  extractDenormalizedReferenceDisplay,
  createMembershipOperation,
  createRoleAssignmentOperation,
  createTenantOperation,
  createWorkspaceOperation
};
//# sourceMappingURL=chunk-4YQD4PFR.mjs.map