import { defineBackendPlugin, createEndpoint } from '@btst/stack/plugins/api';
import { z } from 'zod';
import { formSchemaToZod, zodToFormSchema } from '../../../../../ui/src/lib/schema-converter.mjs';
import { cmsSchema } from '../db.mjs';
import { listContentQuerySchema } from '../schemas.mjs';
import { slugify } from '../utils.mjs';

function migrateToUnifiedSchema(jsonSchemaStr, fieldConfigStr) {
  if (!fieldConfigStr) {
    return jsonSchemaStr;
  }
  try {
    const jsonSchema = JSON.parse(jsonSchemaStr);
    const fieldConfig = JSON.parse(fieldConfigStr);
    if (!jsonSchema.properties || typeof fieldConfig !== "object") {
      return jsonSchemaStr;
    }
    for (const [key, config] of Object.entries(fieldConfig)) {
      if (jsonSchema.properties[key] && typeof config === "object" && config !== null && "fieldType" in config) {
        jsonSchema.properties[key].fieldType = config.fieldType;
      }
    }
    return JSON.stringify(jsonSchema);
  } catch {
    return jsonSchemaStr;
  }
}
function serializeContentType(ct) {
  const needsMigration = !ct.autoFormVersion || ct.autoFormVersion < 2;
  const migratedJsonSchema = needsMigration ? migrateToUnifiedSchema(ct.jsonSchema, ct.fieldConfig) : ct.jsonSchema;
  return {
    id: ct.id,
    name: ct.name,
    slug: ct.slug,
    description: ct.description,
    jsonSchema: migratedJsonSchema,
    createdAt: ct.createdAt.toISOString(),
    updatedAt: ct.updatedAt.toISOString()
  };
}
function serializeContentItem(item) {
  return {
    ...item,
    createdAt: item.createdAt.toISOString(),
    updatedAt: item.updatedAt.toISOString()
  };
}
function serializeContentItemWithType(item) {
  return {
    ...serializeContentItem(item),
    parsedData: JSON.parse(item.data),
    contentType: item.contentType ? serializeContentType(item.contentType) : void 0
  };
}
async function syncContentTypes(adapter, config) {
  for (const ct of config.contentTypes) {
    const jsonSchema = JSON.stringify(zodToFormSchema(ct.schema));
    const existing = await adapter.findOne({
      model: "contentType",
      where: [{ field: "slug", value: ct.slug, operator: "eq" }]
    });
    if (existing) {
      await adapter.update({
        model: "contentType",
        where: [{ field: "id", value: existing.id, operator: "eq" }],
        update: {
          name: ct.name,
          description: ct.description ?? null,
          jsonSchema,
          fieldConfig: null,
          // No longer used in version 2
          autoFormVersion: 2,
          updatedAt: /* @__PURE__ */ new Date()
        }
      });
    } else {
      try {
        await adapter.create({
          model: "contentType",
          data: {
            name: ct.name,
            slug: ct.slug,
            description: ct.description ?? null,
            jsonSchema,
            fieldConfig: null,
            // No longer used in version 2
            autoFormVersion: 2,
            createdAt: /* @__PURE__ */ new Date(),
            updatedAt: /* @__PURE__ */ new Date()
          }
        });
      } catch (err) {
        const nowExists = await adapter.findOne({
          model: "contentType",
          where: [{ field: "slug", value: ct.slug, operator: "eq" }]
        });
        if (nowExists) {
          continue;
        }
        const message = err instanceof Error ? err.message : "Unknown database error";
        throw new Error(
          `Failed to create content type "${ct.slug}": ${message}`
        );
      }
    }
  }
}
function getContentTypeZodSchema(contentType) {
  const jsonSchema = JSON.parse(contentType.jsonSchema);
  return formSchemaToZod(jsonSchema);
}
function extractRelationFields(contentType) {
  const jsonSchema = JSON.parse(
    contentType.jsonSchema
  );
  const properties = jsonSchema.properties || {};
  const relationFields = {};
  for (const [fieldName, fieldSchema] of Object.entries(properties)) {
    if (fieldSchema.fieldType === "relation" && fieldSchema.relation) {
      relationFields[fieldName] = fieldSchema.relation;
    }
  }
  return relationFields;
}
function isNewRelationValue(value) {
  return typeof value === "object" && value !== null && "_new" in value && value._new === true && "data" in value;
}
function isExistingRelationValue(value) {
  return typeof value === "object" && value !== null && "id" in value && typeof value.id === "string";
}
async function processRelationsInData(adapter, contentType, data, getContentTypeFn) {
  const relationFields = extractRelationFields(contentType);
  const processedData = { ...data };
  const relationIds = {};
  for (const [fieldName, relationConfig] of Object.entries(relationFields)) {
    if (!(fieldName in data)) {
      continue;
    }
    const fieldValue = data[fieldName];
    if (!fieldValue) {
      relationIds[fieldName] = [];
      continue;
    }
    const targetContentType = await getContentTypeFn(relationConfig.targetType);
    if (!targetContentType) {
      throw new Error(
        `Target content type "${relationConfig.targetType}" not found for relation field "${fieldName}"`
      );
    }
    const ids = [];
    if (relationConfig.type === "belongsTo") {
      const value = fieldValue;
      if (isNewRelationValue(value)) {
        const newItem = await createRelatedItem(
          adapter,
          targetContentType,
          value.data
        );
        ids.push(newItem.id);
        processedData[fieldName] = { id: newItem.id };
      } else if (isExistingRelationValue(value)) {
        ids.push(value.id);
      }
    } else {
      const values = Array.isArray(fieldValue) ? fieldValue : [];
      const processedValues = [];
      for (const value of values) {
        if (isNewRelationValue(value)) {
          const newItem = await createRelatedItem(
            adapter,
            targetContentType,
            value.data
          );
          ids.push(newItem.id);
          processedValues.push({ id: newItem.id });
        } else if (isExistingRelationValue(value)) {
          ids.push(value.id);
          processedValues.push({ id: value.id });
        }
      }
      processedData[fieldName] = processedValues;
    }
    relationIds[fieldName] = ids;
  }
  return { processedData, relationIds };
}
async function createRelatedItem(adapter, targetContentType, data) {
  const slug = slugify(
    data.slug || data.name || data.title || `item-${Date.now()}`
  );
  const zodSchema = getContentTypeZodSchema(targetContentType);
  const validation = zodSchema.safeParse(data);
  if (!validation.success) {
    throw new Error(
      `Validation failed for new ${targetContentType.slug}: ${JSON.stringify(validation.error.issues)}`
    );
  }
  const existing = await adapter.findOne({
    model: "contentItem",
    where: [
      {
        field: "contentTypeId",
        value: targetContentType.id,
        operator: "eq"
      },
      { field: "slug", value: slug, operator: "eq" }
    ]
  });
  if (existing) {
    return existing;
  }
  const item = await adapter.create({
    model: "contentItem",
    data: {
      contentTypeId: targetContentType.id,
      slug,
      data: JSON.stringify(validation.data),
      createdAt: /* @__PURE__ */ new Date(),
      updatedAt: /* @__PURE__ */ new Date()
    }
  });
  return item;
}
async function syncRelations(adapter, sourceId, relationIds) {
  for (const [fieldName, targetIds] of Object.entries(relationIds)) {
    await adapter.delete({
      model: "contentRelation",
      where: [
        { field: "sourceId", value: sourceId, operator: "eq" },
        { field: "fieldName", value: fieldName, operator: "eq" }
      ]
    });
    for (const targetId of targetIds) {
      await adapter.create({
        model: "contentRelation",
        data: {
          sourceId,
          targetId,
          fieldName,
          createdAt: /* @__PURE__ */ new Date()
        }
      });
    }
  }
}
async function populateRelations(adapter, item) {
  const relations = {};
  const contentRelations = await adapter.findMany({
    model: "contentRelation",
    where: [{ field: "sourceId", value: item.id, operator: "eq" }]
  });
  const relationsByField = {};
  for (const rel of contentRelations) {
    if (!relationsByField[rel.fieldName]) {
      relationsByField[rel.fieldName] = [];
    }
    relationsByField[rel.fieldName].push(rel.targetId);
  }
  for (const [fieldName, targetIds] of Object.entries(relationsByField)) {
    if (targetIds.length === 0) {
      relations[fieldName] = [];
      continue;
    }
    const relatedItems = [];
    for (const targetId of targetIds) {
      const relatedItem = await adapter.findOne({
        model: "contentItem",
        where: [{ field: "id", value: targetId, operator: "eq" }],
        join: { contentType: true }
      });
      if (relatedItem) {
        relatedItems.push(serializeContentItemWithType(relatedItem));
      }
    }
    relations[fieldName] = relatedItems;
  }
  return relations;
}
const cmsBackendPlugin = (config) => defineBackendPlugin({
  name: "cms",
  dbPlugin: cmsSchema,
  routes: (adapter) => {
    let syncPromise = null;
    const ensureSynced = async () => {
      if (!syncPromise) {
        syncPromise = syncContentTypes(adapter, config).catch((err) => {
          syncPromise = null;
          throw err;
        });
      }
      await syncPromise;
    };
    const getContentType = async (slug) => {
      await ensureSynced();
      return adapter.findOne({
        model: "contentType",
        where: [{ field: "slug", value: slug, operator: "eq" }]
      });
    };
    const createContext = (typeSlug, headers) => ({
      typeSlug,
      headers
    });
    const listContentTypes = createEndpoint(
      "/content-types",
      { method: "GET" },
      async (ctx) => {
        await ensureSynced();
        const contentTypes = await adapter.findMany({
          model: "contentType",
          sortBy: { field: "name", direction: "asc" }
        });
        const typesWithCounts = await Promise.all(
          contentTypes.map(async (ct) => {
            const items = await adapter.findMany({
              model: "contentItem",
              where: [
                {
                  field: "contentTypeId",
                  value: ct.id,
                  operator: "eq"
                }
              ]
            });
            return {
              ...serializeContentType(ct),
              itemCount: items.length
            };
          })
        );
        return typesWithCounts;
      }
    );
    const getContentTypeBySlug = createEndpoint(
      "/content-types/:slug",
      {
        method: "GET",
        params: z.object({ slug: z.string() })
      },
      async (ctx) => {
        const { slug } = ctx.params;
        const contentType = await getContentType(slug);
        if (!contentType) {
          throw ctx.error(404, { message: "Content type not found" });
        }
        return serializeContentType(contentType);
      }
    );
    const listContentItems = createEndpoint(
      "/content/:typeSlug",
      {
        method: "GET",
        params: z.object({ typeSlug: z.string() }),
        query: listContentQuerySchema
      },
      async (ctx) => {
        const { typeSlug } = ctx.params;
        const { slug, limit, offset } = ctx.query;
        const contentType = await getContentType(typeSlug);
        if (!contentType) {
          throw ctx.error(404, { message: "Content type not found" });
        }
        const whereConditions = [
          {
            field: "contentTypeId",
            value: contentType.id,
            operator: "eq"
          }
        ];
        if (slug) {
          whereConditions.push({
            field: "slug",
            value: slug,
            operator: "eq"
          });
        }
        const allItems = await adapter.findMany({
          model: "contentItem",
          where: whereConditions
        });
        const total = allItems.length;
        const items = await adapter.findMany({
          model: "contentItem",
          where: whereConditions,
          limit,
          offset,
          sortBy: { field: "createdAt", direction: "desc" },
          join: { contentType: true }
        });
        return {
          items: items.map(serializeContentItemWithType),
          total,
          limit,
          offset
        };
      }
    );
    const getContentItem = createEndpoint(
      "/content/:typeSlug/:id",
      {
        method: "GET",
        params: z.object({ typeSlug: z.string(), id: z.string() })
      },
      async (ctx) => {
        const { typeSlug, id } = ctx.params;
        const contentType = await getContentType(typeSlug);
        if (!contentType) {
          throw ctx.error(404, { message: "Content type not found" });
        }
        const item = await adapter.findOne({
          model: "contentItem",
          where: [{ field: "id", value: id, operator: "eq" }],
          join: { contentType: true }
        });
        if (!item || item.contentTypeId !== contentType.id) {
          throw ctx.error(404, { message: "Content item not found" });
        }
        return serializeContentItemWithType(item);
      }
    );
    const createContentItem = createEndpoint(
      "/content/:typeSlug",
      {
        method: "POST",
        params: z.object({ typeSlug: z.string() }),
        body: z.object({
          slug: z.string().min(1),
          // Use passthrough object instead of z.record(z.unknown()) due to Zod v4 bug
          data: z.object({}).passthrough()
        })
      },
      async (ctx) => {
        const { typeSlug } = ctx.params;
        const { slug: rawSlug, data } = ctx.body;
        const context = createContext(typeSlug, ctx.headers);
        const slug = slugify(rawSlug);
        if (!slug) {
          throw ctx.error(400, {
            message: "Invalid slug: must contain at least one alphanumeric character"
          });
        }
        const contentType = await getContentType(typeSlug);
        if (!contentType) {
          throw ctx.error(404, { message: "Content type not found" });
        }
        const { processedData: dataWithResolvedRelations, relationIds } = await processRelationsInData(
          adapter,
          contentType,
          data,
          getContentType
        );
        const zodSchema = getContentTypeZodSchema(contentType);
        const validation = zodSchema.safeParse(dataWithResolvedRelations);
        if (!validation.success) {
          throw ctx.error(400, {
            message: "Validation failed",
            errors: validation.error.issues
          });
        }
        const existing = await adapter.findOne({
          model: "contentItem",
          where: [
            {
              field: "contentTypeId",
              value: contentType.id,
              operator: "eq"
            },
            { field: "slug", value: slug, operator: "eq" }
          ]
        });
        if (existing) {
          throw ctx.error(409, {
            message: "Content item with this slug already exists"
          });
        }
        const processedData = validation.data;
        if (config.hooks?.onBeforeCreate) {
          const result = await config.hooks.onBeforeCreate(
            processedData,
            context
          );
          if (result === false) {
            throw ctx.error(403, { message: "Create operation denied" });
          }
        }
        const item = await adapter.create({
          model: "contentItem",
          data: {
            contentTypeId: contentType.id,
            slug,
            data: JSON.stringify(processedData),
            createdAt: /* @__PURE__ */ new Date(),
            updatedAt: /* @__PURE__ */ new Date()
          }
        });
        await syncRelations(adapter, item.id, relationIds);
        const serialized = serializeContentItem(item);
        if (config.hooks?.onAfterCreate) {
          await config.hooks.onAfterCreate(serialized, context);
        }
        return {
          ...serialized,
          parsedData: processedData
        };
      }
    );
    const updateContentItem = createEndpoint(
      "/content/:typeSlug/:id",
      {
        method: "PUT",
        params: z.object({ typeSlug: z.string(), id: z.string() }),
        body: z.object({
          slug: z.string().min(1).optional(),
          // Use passthrough object instead of z.record(z.unknown()) due to Zod v4 bug
          data: z.object({}).passthrough().optional()
        })
      },
      async (ctx) => {
        const { typeSlug, id } = ctx.params;
        const { slug: rawSlug, data } = ctx.body;
        const context = createContext(typeSlug, ctx.headers);
        const slug = rawSlug ? slugify(rawSlug) : void 0;
        if (rawSlug && !slug) {
          throw ctx.error(400, {
            message: "Invalid slug: must contain at least one alphanumeric character"
          });
        }
        const contentType = await getContentType(typeSlug);
        if (!contentType) {
          throw ctx.error(404, { message: "Content type not found" });
        }
        const existing = await adapter.findOne({
          model: "contentItem",
          where: [{ field: "id", value: id, operator: "eq" }]
        });
        if (!existing || existing.contentTypeId !== contentType.id) {
          throw ctx.error(404, { message: "Content item not found" });
        }
        if (slug && slug !== existing.slug) {
          const duplicate = await adapter.findOne({
            model: "contentItem",
            where: [
              {
                field: "contentTypeId",
                value: contentType.id,
                operator: "eq"
              },
              { field: "slug", value: slug, operator: "eq" }
            ]
          });
          if (duplicate) {
            throw ctx.error(409, {
              message: "Content item with this slug already exists"
            });
          }
        }
        let dataWithResolvedRelations;
        let relationIds;
        if (data) {
          const result = await processRelationsInData(
            adapter,
            contentType,
            data,
            getContentType
          );
          dataWithResolvedRelations = result.processedData;
          relationIds = result.relationIds;
        }
        let validatedData = dataWithResolvedRelations;
        if (dataWithResolvedRelations) {
          const existingData = existing.data ? JSON.parse(existing.data) : {};
          const mergedData = {
            ...existingData,
            ...dataWithResolvedRelations
          };
          const zodSchema = getContentTypeZodSchema(contentType);
          const validation = zodSchema.safeParse(mergedData);
          if (!validation.success) {
            throw ctx.error(400, {
              message: "Validation failed",
              errors: validation.error.issues
            });
          }
          validatedData = validation.data;
        }
        const processedData = validatedData;
        if (config.hooks?.onBeforeUpdate && validatedData) {
          const result = await config.hooks.onBeforeUpdate(
            id,
            validatedData,
            context
          );
          if (result === false) {
            throw ctx.error(403, { message: "Update operation denied" });
          }
        }
        if (relationIds) {
          await syncRelations(adapter, id, relationIds);
        }
        const updateData = {
          updatedAt: /* @__PURE__ */ new Date()
        };
        if (slug) updateData.slug = slug;
        if (processedData) updateData.data = JSON.stringify(processedData);
        await adapter.update({
          model: "contentItem",
          where: [{ field: "id", value: id, operator: "eq" }],
          update: updateData
        });
        const updated = await adapter.findOne({
          model: "contentItem",
          where: [{ field: "id", value: id, operator: "eq" }],
          join: { contentType: true }
        });
        if (!updated) {
          throw ctx.error(500, { message: "Failed to fetch updated item" });
        }
        const serialized = serializeContentItem(updated);
        if (config.hooks?.onAfterUpdate) {
          await config.hooks.onAfterUpdate(serialized, context);
        }
        return serializeContentItemWithType(updated);
      }
    );
    const deleteContentItem = createEndpoint(
      "/content/:typeSlug/:id",
      {
        method: "DELETE",
        params: z.object({ typeSlug: z.string(), id: z.string() })
      },
      async (ctx) => {
        const { typeSlug, id } = ctx.params;
        const context = createContext(typeSlug, ctx.headers);
        const contentType = await getContentType(typeSlug);
        if (!contentType) {
          throw ctx.error(404, { message: "Content type not found" });
        }
        const existing = await adapter.findOne({
          model: "contentItem",
          where: [{ field: "id", value: id, operator: "eq" }]
        });
        if (!existing || existing.contentTypeId !== contentType.id) {
          throw ctx.error(404, { message: "Content item not found" });
        }
        if (config.hooks?.onBeforeDelete) {
          const canDelete = await config.hooks.onBeforeDelete(id, context);
          if (!canDelete) {
            throw ctx.error(403, { message: "Delete operation denied" });
          }
        }
        await adapter.delete({
          model: "contentItem",
          where: [{ field: "id", value: id, operator: "eq" }]
        });
        if (config.hooks?.onAfterDelete) {
          await config.hooks.onAfterDelete(id, context);
        }
        return { success: true };
      }
    );
    const getContentItemPopulated = createEndpoint(
      "/content/:typeSlug/:id/populated",
      {
        method: "GET",
        params: z.object({ typeSlug: z.string(), id: z.string() })
      },
      async (ctx) => {
        const { typeSlug, id } = ctx.params;
        const contentType = await getContentType(typeSlug);
        if (!contentType) {
          throw ctx.error(404, { message: "Content type not found" });
        }
        const item = await adapter.findOne({
          model: "contentItem",
          where: [{ field: "id", value: id, operator: "eq" }],
          join: { contentType: true }
        });
        if (!item || item.contentTypeId !== contentType.id) {
          throw ctx.error(404, { message: "Content item not found" });
        }
        const _relations = await populateRelations(adapter, item);
        return {
          ...serializeContentItemWithType(item),
          _relations
        };
      }
    );
    const listContentByRelation = createEndpoint(
      "/content/:typeSlug/by-relation",
      {
        method: "GET",
        params: z.object({ typeSlug: z.string() }),
        query: z.object({
          field: z.string(),
          targetId: z.string(),
          limit: z.coerce.number().min(1).max(100).optional().default(20),
          offset: z.coerce.number().min(0).optional().default(0)
        })
      },
      async (ctx) => {
        const { typeSlug } = ctx.params;
        const { field, targetId, limit, offset } = ctx.query;
        const contentType = await getContentType(typeSlug);
        if (!contentType) {
          throw ctx.error(404, { message: "Content type not found" });
        }
        const contentRelations = await adapter.findMany({
          model: "contentRelation",
          where: [
            { field: "targetId", value: targetId, operator: "eq" },
            { field: "fieldName", value: field, operator: "eq" }
          ]
        });
        const sourceIds = [
          ...new Set(contentRelations.map((r) => r.sourceId))
        ];
        if (sourceIds.length === 0) {
          return {
            items: [],
            total: 0,
            limit,
            offset
          };
        }
        const allItems = [];
        for (const sourceId of sourceIds) {
          const item = await adapter.findOne({
            model: "contentItem",
            where: [
              { field: "id", value: sourceId, operator: "eq" },
              {
                field: "contentTypeId",
                value: contentType.id,
                operator: "eq"
              }
            ],
            join: { contentType: true }
          });
          if (item) {
            allItems.push(item);
          }
        }
        allItems.sort(
          (a, b) => b.createdAt.getTime() - a.createdAt.getTime()
        );
        const total = allItems.length;
        const paginatedItems = allItems.slice(offset, offset + limit);
        return {
          items: paginatedItems.map(serializeContentItemWithType),
          total,
          limit,
          offset
        };
      }
    );
    const getInverseRelations = createEndpoint(
      "/content-types/:slug/inverse-relations",
      {
        method: "GET",
        params: z.object({ slug: z.string() }),
        query: z.object({
          itemId: z.string().optional()
        })
      },
      async (ctx) => {
        const { slug } = ctx.params;
        const { itemId } = ctx.query;
        await ensureSynced();
        const targetContentType = await getContentType(slug);
        if (!targetContentType) {
          throw ctx.error(404, { message: "Content type not found" });
        }
        const allContentTypes = await adapter.findMany({
          model: "contentType"
        });
        const inverseRelations = [];
        for (const contentType of allContentTypes) {
          const relationFields = extractRelationFields(contentType);
          for (const [fieldName, relationConfig] of Object.entries(
            relationFields
          )) {
            if (relationConfig.type === "belongsTo" && relationConfig.targetType === slug) {
              let count = 0;
              if (itemId) {
                const relations = await adapter.findMany({
                  model: "contentRelation",
                  where: [
                    {
                      field: "targetId",
                      value: itemId,
                      operator: "eq"
                    },
                    {
                      field: "fieldName",
                      value: fieldName,
                      operator: "eq"
                    }
                  ]
                });
                const itemIds = relations.map((r) => r.sourceId);
                for (const sourceId of itemIds) {
                  const item = await adapter.findOne({
                    model: "contentItem",
                    where: [
                      {
                        field: "id",
                        value: sourceId,
                        operator: "eq"
                      },
                      {
                        field: "contentTypeId",
                        value: contentType.id,
                        operator: "eq"
                      }
                    ]
                  });
                  if (item) count++;
                }
              }
              inverseRelations.push({
                sourceType: contentType.slug,
                sourceTypeName: contentType.name,
                fieldName,
                count
              });
            }
          }
        }
        return { inverseRelations };
      }
    );
    const listInverseRelationItems = createEndpoint(
      "/content-types/:slug/inverse-relations/:sourceType",
      {
        method: "GET",
        params: z.object({
          slug: z.string(),
          sourceType: z.string()
        }),
        query: z.object({
          itemId: z.string(),
          fieldName: z.string(),
          limit: z.coerce.number().min(1).max(100).optional().default(20),
          offset: z.coerce.number().min(0).optional().default(0)
        })
      },
      async (ctx) => {
        const { slug, sourceType } = ctx.params;
        const { itemId, fieldName, limit, offset } = ctx.query;
        await ensureSynced();
        const targetContentType = await getContentType(slug);
        if (!targetContentType) {
          throw ctx.error(404, { message: "Target content type not found" });
        }
        const sourceContentType = await getContentType(sourceType);
        if (!sourceContentType) {
          throw ctx.error(404, { message: "Source content type not found" });
        }
        const relations = await adapter.findMany({
          model: "contentRelation",
          where: [
            { field: "targetId", value: itemId, operator: "eq" },
            { field: "fieldName", value: fieldName, operator: "eq" }
          ]
        });
        const sourceIds = [...new Set(relations.map((r) => r.sourceId))];
        const allItems = [];
        for (const sourceId of sourceIds) {
          const item = await adapter.findOne({
            model: "contentItem",
            where: [
              { field: "id", value: sourceId, operator: "eq" },
              {
                field: "contentTypeId",
                value: sourceContentType.id,
                operator: "eq"
              }
            ],
            join: { contentType: true }
          });
          if (item) {
            allItems.push(item);
          }
        }
        allItems.sort(
          (a, b) => b.createdAt.getTime() - a.createdAt.getTime()
        );
        const total = allItems.length;
        const paginatedItems = allItems.slice(offset, offset + limit);
        return {
          items: paginatedItems.map(serializeContentItemWithType),
          total,
          limit,
          offset
        };
      }
    );
    return {
      listContentTypes,
      getContentTypeBySlug,
      listContentItems,
      getContentItem,
      createContentItem,
      updateContentItem,
      deleteContentItem,
      getContentItemPopulated,
      listContentByRelation,
      getInverseRelations,
      listInverseRelationItems
    };
  }
});

export { cmsBackendPlugin };
