import { a as getSchemaManager, br as getComponentRegistry, b as getDatabaseManager, E as dbQuery, c as createError } from '../nitro/nitro.mjs';

const SKIP_SCHEMAS = /* @__PURE__ */ new Set(["media", "media-folder", "admin-user", "role"]);
const SAFE_IDENTIFIER_RE = /^[A-Za-z_][A-Za-z0-9_]*$/;
async function findMediaUsages(mediaId) {
  const schemaManager = getSchemaManager();
  const allSchemas = schemaManager.getAllSchemas();
  const components = indexComponents(getComponentRegistry().getAll());
  const db = getDatabaseManager();
  const usages = [];
  for (const schema of allSchemas) {
    const singularName = schema.info.singularName;
    if (SKIP_SCHEMAS.has(singularName)) {
      continue;
    }
    const tableName = schema.info.pluralName.replace(/-/g, "_");
    if (!isSafeIdentifier(tableName)) {
      continue;
    }
    const candidates = collectUsageCandidates(schema, components);
    if (candidates.length === 0) {
      continue;
    }
    const titleColumn = getTitleColumn(schema.attributes);
    const selectableColumns = /* @__PURE__ */ new Set([
      "id",
      ...candidates.map((candidate) => candidate.columnName)
    ]);
    if (titleColumn !== "id") {
      selectableColumns.add(titleColumn);
    }
    const safeColumns = [...selectableColumns].filter(isSafeIdentifier);
    const quotedTable = db.quoteIdentifier(tableName);
    const quotedId = db.quoteIdentifier("id");
    const selectColumns = safeColumns.map((column) => db.quoteIdentifier(column)).join(", ");
    const titleExpression = titleColumn !== "id" && isSafeIdentifier(titleColumn) ? `${db.quoteIdentifier(titleColumn)} AS _title` : `${quotedId} AS _title`;
    const singleMediaCandidates = candidates.filter(
      (candidate) => candidate.mode === "singleMedia"
    );
    const hasCompositeCandidates = candidates.some((candidate) => candidate.mode === "composite");
    const whereParts = hasCompositeCandidates ? [] : singleMediaCandidates.filter((candidate) => isSafeIdentifier(candidate.columnName)).map((candidate) => `${db.quoteIdentifier(candidate.columnName)} = ?`);
    const params = hasCompositeCandidates ? [] : singleMediaCandidates.map(() => mediaId);
    const whereClause = whereParts.length > 0 ? ` WHERE ${whereParts.join(" OR ")}` : "";
    try {
      const rows = await dbQuery(
        `SELECT ${selectColumns}, ${titleExpression} FROM ${quotedTable}${whereClause}`,
        params,
        { forcePrimary: true }
      );
      for (const row of rows) {
        for (const candidate of candidates) {
          const value = row[candidate.columnName];
          const fieldMatches = candidate.mode === "singleMedia" ? mediaValueMatches(value, mediaId, false) : collectMediaFieldPaths(
            value,
            candidate.field,
            candidate.fieldName,
            mediaId,
            components
          );
          if (Array.isArray(fieldMatches)) {
            for (const fieldName of fieldMatches) {
              usages.push(toUsageEntry(schema, row, fieldName));
            }
          } else if (fieldMatches) {
            usages.push(toUsageEntry(schema, row, candidate.fieldName));
          }
        }
      }
    } catch {
      continue;
    }
  }
  return dedupeUsages(usages);
}
async function assertMediaNotInUse(mediaId) {
  const usages = await findMediaUsages(mediaId);
  if (usages.length === 0) {
    return;
  }
  throw createError({
    statusCode: 409,
    statusMessage: "Conflict",
    message: `Media file is used by ${usages.length} content reference(s). Remove references before deleting it.`,
    data: { usages, total: usages.length }
  });
}
function collectUsageCandidates(schema, components) {
  const candidates = [];
  for (const [fieldName, field] of Object.entries(schema.attributes)) {
    if (field.type === "media") {
      candidates.push({
        fieldName,
        columnName: field.multiple ? fieldName : `${fieldName}_id`,
        field,
        mode: field.multiple ? "composite" : "singleMedia"
      });
      continue;
    }
    if (fieldContainsMedia(field, components)) {
      candidates.push({
        fieldName,
        columnName: fieldName,
        field,
        mode: "composite"
      });
    }
  }
  return candidates.filter((candidate) => isSafeIdentifier(candidate.columnName));
}
function fieldContainsMedia(field, components) {
  if (field.type === "media") {
    return true;
  }
  if (field.type === "component" && field.component) {
    const component = components.get(field.component);
    return component ? attributesContainMedia(component.attributes, components) : false;
  }
  if (field.type === "dynamicZone" && Array.isArray(field.components)) {
    return field.components.some((uid) => {
      const component = components.get(uid);
      return component ? attributesContainMedia(component.attributes, components) : false;
    });
  }
  return false;
}
function attributesContainMedia(attributes, components) {
  return Object.values(attributes).some((field) => fieldContainsMedia(field, components));
}
function collectMediaFieldPaths(rawValue, field, fieldPath, mediaId, components) {
  const value = parseJsonValue(rawValue);
  if (field.type === "media") {
    return mediaValueMatches(value, mediaId, Boolean(field.multiple)) ? [fieldPath] : [];
  }
  if (field.type === "component" && field.component) {
    const component = components.get(field.component);
    if (!component) {
      return [];
    }
    const values = field.repeatable ? toArray(value) : value === null || value === void 0 ? [] : [value];
    return values.flatMap(
      (item, index) => collectFromComponentValue(
        item,
        component,
        field.repeatable ? `${fieldPath}[${index}]` : fieldPath,
        mediaId,
        components
      )
    );
  }
  if (field.type === "dynamicZone") {
    return toArray(value).flatMap((item, index) => {
      var _a;
      if (!item || typeof item !== "object" || Array.isArray(item)) {
        return [];
      }
      const componentUid = String((_a = item.__component) != null ? _a : "");
      const component = components.get(componentUid);
      if (!component) {
        return [];
      }
      return collectFromComponentValue(
        item,
        component,
        `${fieldPath}[${index}:${componentUid}]`,
        mediaId,
        components
      );
    });
  }
  return [];
}
function collectFromComponentValue(value, component, fieldPath, mediaId, components) {
  const parsedValue = parseJsonValue(value);
  if (!parsedValue || typeof parsedValue !== "object" || Array.isArray(parsedValue)) {
    return [];
  }
  const record = parsedValue;
  return Object.entries(component.attributes).flatMap(
    ([childFieldName, childField]) => collectMediaFieldPaths(
      record[childFieldName],
      childField,
      `${fieldPath}.${childFieldName}`,
      mediaId,
      components
    )
  );
}
function mediaValueMatches(value, mediaId, multiple) {
  if (multiple) {
    return toArray(parseJsonValue(value)).some((item) => mediaValueMatches(item, mediaId, false));
  }
  const parsed = parseJsonValue(value);
  if (parsed && typeof parsed === "object" && !Array.isArray(parsed) && "id" in parsed) {
    return Number(parsed.id) === mediaId;
  }
  return Number(parsed) === mediaId;
}
function parseJsonValue(value) {
  if (typeof value !== "string") {
    return value;
  }
  try {
    return JSON.parse(value);
  } catch {
    return value;
  }
}
function toArray(value) {
  return Array.isArray(value) ? value : [];
}
function getTitleColumn(attributes) {
  const titleCandidates = ["title", "name", "displayName", "label", "subject", "heading"];
  for (const candidate of titleCandidates) {
    const field = attributes[candidate];
    if (field && (field.type === "string" || field.type === "text") && isSafeIdentifier(candidate)) {
      return candidate;
    }
  }
  return "id";
}
function toUsageEntry(schema, row, fieldName) {
  var _a;
  return {
    contentType: schema.info.singularName,
    displayName: schema.info.displayName,
    entryId: Number(row.id),
    entryTitle: String((_a = row._title) != null ? _a : `#${row.id}`),
    fieldName
  };
}
function dedupeUsages(usages) {
  const seen = /* @__PURE__ */ new Set();
  const deduped = [];
  for (const usage of usages) {
    const key = `${usage.contentType}:${usage.entryId}:${usage.fieldName}`;
    if (seen.has(key)) {
      continue;
    }
    seen.add(key);
    deduped.push(usage);
  }
  return deduped;
}
function indexComponents(components) {
  return new Map(components.map((component) => [component.uid, component]));
}
function isSafeIdentifier(value) {
  return SAFE_IDENTIFIER_RE.test(value);
}

export { assertMediaNotInUse as a, findMediaUsages as f };
//# sourceMappingURL=media-usage.mjs.map
