import { isDefined } from "ts-is-present";
import {
  isDiscriminatorForm,
  isElementsForm,
  isEmptyForm,
  isEnumForm,
  isPropertiesForm,
  isRefForm,
  isTypeForm,
  isValuesForm
} from "./json-typedef-js-fork/schema.js";
function jtdToMd(schema, renderExamples) {
  const usedBy = collectUsedBy("RicosDocument", schema);
  const output = { root: [] };
  const rest = [
    { name: "RicosDocument", usedByRefs: [], schema: { ...schema, metadata: { section: "root" } } },
    ...Object.keys(schema.definitions || {}).map((name) => ({
      name,
      usedByRefs: usedBy[name] ?? [],
      schema: schema.definitions[name]
    }))
  ];
  while (rest.length > 0) {
    const current = rest.shift();
    if (!current) {
      throw new Error("Unexpected undefined");
    }
    const { output: currentOutput, rest: currentRest } = renderSchema({
      name: current.name,
      schema: current.schema,
      usedByRefs: current.usedByRefs,
      definitions: schema.definitions || {},
      renderExamples
    });
    const section = current.schema?.metadata?.section ?? "Common";
    output[section] = output[section] || [];
    output[section].push(currentOutput);
    if (currentRest) {
      rest.push(
        ...currentRest.map((restItem) => ({ ...restItem, usedByRefs: usedBy[restItem.name] ?? [] }))
      );
    }
  }
  const result = Object.keys(output).reduce((acc, section) => {
    acc[section] = output[section].join("\n\n");
    return acc;
  }, {});
  result.Formats = renderMdTable(
    [
      { key: "format", label: "Format" },
      { key: "description", label: "Description" }
    ],
    Object.keys(schema.metadata?.formats || {}).map((format) => ({
      format,
      description: schema.metadata.formats[format].description
    }))
  );
  return result;
}
function renderSchema({
  name,
  schema,
  usedByRefs,
  definitions,
  renderExamples
}) {
  if (schema.metadata?.internal) {
    return { output: "", rest: [] };
  }
  const docs = schema.metadata?.description ? `${schema.metadata.description}

` : "";
  const usedBy = usedByRefs.length > 0 ? `**Used in:** ${usedByRefs.map(typeLink).join(", ")}

` : "";
  const plugins = getPluginsByFeatures(schema.metadata?.features);
  const enabledBy = plugins.length > 0 ? `<blockquote class='info'><p>${plugins.map((p) => `<span id="plugin-${p}"></span>`).join("")}<b>Note:</b> This type requires the ${plugins.map((p) => `\`${p}\``).join(
    ", "
  )} <a href="https://dev.wix.com/docs/ricos/getting-started/introduction#plugins">${plugins.length > 1 ? "plugins" : "plugin"} to be enabled.</a></p></blockquote>

` : "";
  const examples = schema.metadata?.examples ? renderExamples(schema.metadata.examples) : "";
  const level = schema.metadata?.examples || ITEMS_FORCED_TO_MENU.includes(name) ? 4 : 5;
  const header = `${"#".repeat(level)} ${getTypeHeading(
    name
  )}

${usedBy}${enabledBy}${docs}${examples}`;
  if (isPropertiesForm(schema)) {
    const { rest, rows } = getPropertiesRows(schema);
    const patterns = rows.filter((row) => !!row.patternWarning).map((row) => row.patternWarning).join("");
    const oneOfs = schema.metadata?.oneOf?.properties || [];
    const oneOfWarning = oneOfs.length ? `

<blockquote class="caution">
  You must provide ${schema.metadata?.oneOf?.strict ? "exactly" : "at least"} one of the following fields: ${oneOfs.map(
      (name2) => getFieldNameBadge({
        fieldName: name2,
        isRequired: false,
        deprecated: false
      })
    ).join(", ")}.
</blockquote>

` : "";
    return {
      output: header + patterns + oneOfWarning + "\n\n" + renderMdTable(
        [
          { key: "name", label: "Field" },
          { key: "type", label: "Type" },
          { key: "description", label: "Description" }
        ],
        rows
      ),
      rest
    };
  }
  if (isTypeForm(schema)) {
    return { output: `${header}\`${schema.type}\``, rest: [] };
  }
  if (isRefForm(schema)) {
    return { output: `TODO: [${schema.ref}](#${schema.ref.toLowerCase()})`, rest: [] };
  }
  if (isEnumForm(schema)) {
    if (schema.enum.length === 1) {
      return { output: `${header} \`"${schema.enum[0]}"\``, rest: [] };
    }
    return {
      output: `${header}\`enum\`: ${schema.enum.map((v) => `\`"${v}"\``).join(", ")}`,
      rest: []
    };
  }
  if (isDiscriminatorForm(schema)) {
    const refUnion = schema.metadata?.refUnion;
    const rows = refUnion ? Object.keys(refUnion).sort().filter((key) => !schema.mapping[key].metadata?.internal).map((key) => {
      const ref = refUnion[key];
      return {
        value: typeLink(ref),
        tag: `\`${key}\``,
        description: definitions[ref].metadata?.description ?? ""
      };
    }) : Object.keys(schema.mapping).sort().filter((key) => !schema.mapping[key].metadata?.internal).map((key) => {
      const memberName = `${name}:${key}`;
      return {
        value: typeLink(memberName),
        tag: `\`${key}\``,
        description: getPluginsByFeatures(schema.mapping[key].metadata?.features).map(getPluginBadge).join(", ") ?? ""
      };
    });
    return {
      output: `${header} _This type is a [Tagged Union](#tagged-unions)._ 

${renderMdTable(
        [
          { key: "value", label: "Variant" },
          { key: "tag", label: "Tag value" },
          { key: "description", label: "Description" }
        ],
        rows
      )}`,
      rest: schema.metadata?.refUnion ? [] : Object.keys(schema.mapping).map((key) => ({
        name: `${name}:${key}`,
        schema: schema.mapping[key]
      }))
    };
  }
  if (isElementsForm(schema)) {
    const renderResult = renderSchemaInCell(schema.elements);
    return {
      output: `\`Array\` ${renderResult.output}`,
      rest: renderResult.rest ? [renderResult.rest] : []
    };
  }
  if (isValuesForm(schema)) {
    return { output: "TODO values", rest: [] };
  }
  if (isEmptyForm(schema)) {
    return { output: "TODO any", rest: [] };
  }
  const _exhaustiveCheck = schema;
  throw new Error("Unknown schema form");
}
function renderSchemaInCell(schema) {
  if (isTypeForm(schema)) {
    const formatBadge = schema.metadata?.format ? getFormatBadge(schema.metadata?.format) : "";
    const validationBadges = getValidationBadges(schema.metadata?.validation || {});
    return {
      output: [`<span class="font-mono">${schema.type}</span>`, formatBadge, ...validationBadges].filter(isDefined).join("<br>")
    };
  }
  if (isRefForm(schema)) {
    return { output: typeLink(schema.ref) };
  }
  if (isEnumForm(schema)) {
    if (schema.enum.length === 1) {
      return { output: `\`"${schema.enum[0]}"\`` };
    }
    return { output: `\`enum\`: ${schema.enum.map((v) => `\`"${v}"\``).join(", ")}` };
  }
  if (isDiscriminatorForm(schema)) {
    return { output: "TODO discriminator", rest: { name: "some Discriminator", schema } };
  }
  if (isElementsForm(schema)) {
    const renderResult = renderSchemaInCell(schema.elements);
    const validationBadges = getValidationBadges(schema.metadata?.validation || {});
    return {
      output: [
        `<span class="font-mono">Array &lt;</span>${renderResult.output}<span class="font-mono">&gt;</span>`,
        ...validationBadges
      ].join("<br>"),
      rest: renderResult.rest
    };
  }
  if (isPropertiesForm(schema)) {
    return { output: "TODO properties" };
  }
  if (isValuesForm(schema)) {
    return { output: "TODO values" };
  }
  if (isEmptyForm(schema)) {
    return { output: '<span class="font-mono">any</a>' };
  }
  const _exhaustiveCheck = schema;
  throw new Error("Unknown schema form");
}
function renderMdTable(header, rows) {
  const headerRow = header.map((cell) => `| ${cell.label} `).join("") + "|";
  const dividerRow = header.map(() => "| :------ ").join("") + "|";
  const bodyRows = rows.map((row) => {
    return header.map((cell) => `| ${row[cell.key]} `).join("") + "|";
  });
  return [headerRow, dividerRow, ...bodyRows].join("\n");
}
function getPropertiesRows(schema) {
  const rows = [];
  const rest = [];
  Object.keys(schema).forEach((key) => {
    if (key === "properties" || key === "optionalProperties") {
      Object.keys(schema[key]).forEach((propertyName) => {
        const propertiesSchema = schema[key];
        const property = propertiesSchema[propertyName];
        if (property.metadata?.internal) {
          return;
        }
        const renderResult = renderSchemaInCell(property);
        const deprecated = !!property.metadata?.deprecated;
        const propertyType = renderResult.output;
        const oneOf = !schema.metadata?.oneOf || !schema.metadata.oneOf.properties.includes(propertyName) ? void 0 : schema.metadata.oneOf.strict ? "STRICT" : "LOOSE";
        const patternWarning = property.metadata?.pattern ? `

<blockquote class="caution">
  <strong>Items in the ${getFieldNameBadge({
          fieldName: propertyName,
          isRequired: false,
          deprecated: false
        })} field must have the following structure and order:</strong>

\`${property.metadata?.pattern.value}\`

${property.metadata?.pattern.description}
</blockquote>

` : "";
        rows.push({
          name: getFieldNameBadge({
            fieldName: propertyName,
            isRequired: key === "properties",
            deprecated,
            oneOf
          }),
          type: propertyType,
          description: (property.metadata?.description ?? "").replace(/\n/g, "<br>") + (patternWarning ? '<br><span class="text-xs tracking-[0.0075em] text-red-600">Array items must adhere to the pattern described above this table.</span>' : ""),
          patternWarning,
          oneOf: !property.metadata?.oneOf ? void 0 : property.metadata?.oneOf.strict ? "STRICT" : "LOOSE"
        });
        if (renderResult.rest) {
          rest.push(renderResult.rest);
        }
      });
    }
  });
  return { rest, rows };
}
function typeLink(title) {
  const slug = title.toLowerCase().replace(/[^\w\s-]/g, "").trim().replace(/\s+/g, "-");
  return `<a href="#${slug}"><span class="font-mono">${title}</span></a>`;
}
function collectUsedBy(rootName, rootSchema) {
  const definitions = rootSchema.definitions || {};
  const result = [];
  const queue = [{ parentName: rootName, schema: rootSchema }];
  const visited = /* @__PURE__ */ new Set();
  while (queue.length > 0) {
    const { schema, parentName } = queue.shift();
    if (visited.has(schema)) {
      continue;
    }
    visited.add(schema);
    if (isPropertiesForm(schema)) {
      Object.values({ ...schema.properties, ...schema.optionalProperties }).forEach((subSchema) => {
        if (isRefForm(subSchema)) {
          result.push({ [subSchema.ref]: parentName });
          queue.push({ parentName: subSchema.ref, schema: definitions[subSchema.ref] });
        } else {
          queue.push({ parentName, schema: subSchema });
        }
      });
      continue;
    }
    if (isDiscriminatorForm(schema)) {
      if (schema.metadata?.refUnion) {
        Object.values(schema.metadata.refUnion).forEach((ref) => {
          result.push({ [ref]: parentName });
          queue.push({ parentName: ref, schema: definitions[ref] });
        });
      }
      continue;
    }
    if (isElementsForm(schema)) {
      queue.push({ parentName, schema: schema.elements });
      continue;
    }
    if (isValuesForm(schema)) {
      queue.push({ parentName, schema: schema.values });
      continue;
    }
    if (isRefForm(schema)) {
      result.push({ [schema.ref]: parentName });
      queue.push({ parentName: schema.ref, schema: definitions[schema.ref] });
      continue;
    }
  }
  return result.reduce(
    (acc, item) => {
      Object.keys(item).forEach((ref) => {
        acc[ref] = acc[ref] ?? [];
        if (!acc[ref].includes(item[ref])) {
          acc[ref].push(item[ref]);
        }
      });
      return acc;
    },
    {}
  );
}
function getPluginBadge(plugin) {
  return `[${plugin}](https://dev.wix.com/docs/ricos/getting-started/introduction#plugins)`;
}
function getFormatBadge(format) {
  return `<a href="#formats"><span style="display:inline-block" class="rounded border-[1px] border-solid border-blue-300 bg-transparent px-1.5 py-[3px] font-mono text-xs font-normal text-slate-900">format ${format}</span></a>`;
}
function getValidationBadges(validation) {
  return Object.keys(validation).map((key) => {
    if (validation[key] === void 0) {
      return void 0;
    }
    const text = key === "uniqueTags" ? "Unique Tags" : key === "minSize" ? `minItems: ${validation[key]}` : key === "maxSize" ? `maxItems: ${validation[key]}` : key === "min" ? `minimum: ${validation.min}` : key === "max" ? `maximum: ${validation.max}` : `${key}: ${validation[key]}`;
    return `<span style="display:inline-block" class="rounded border-[1px] border-solid border-blue-300 bg-transparent px-1.5 py-[3px] font-mono text-xs font-normal text-slate-900">${text}</span>`;
  }).filter(isDefined);
}
function getFieldNameBadge({
  fieldName,
  isRequired,
  deprecated,
  oneOf
}) {
  return `<span style="${deprecated ? "text-decoration: line-through;" : ""}" class="rounded border-[1px] border-blue-300 font-mono border-none bg-blue-100 px-3 py-1.5 text-sm font-medium leading-[18px] tracking-[0.0175em] text-[#224670]">${fieldName}</span>${oneOf ? `<br><span style="line-height: 28px" class="font-mono text-xs tracking-[0.0075em] text-red-600">${oneOf === "STRICT" ? "Exactly one of" : "At least one of"}</span>` : ""}${isRequired ? '<br><span style="line-height: 28px" class="font-mono text-xs tracking-[0.0075em] text-red-600">Required</span>' : ""}${deprecated ? '<br><span style="line-height: 28px" class="font-mono text-xs tracking-[0.0075em] text-red-600">Deprecated</span>' : ""}`;
}
function getTypeHeading(typeName) {
  return `<span style="font-weight: 700;" class="rounded-lg border-[1px] border-blue-300 font-mono border-none bg-blue-100 px-2 py-1 leading-[18px] tracking-[0.0175em] font-bold text-slate-900">${typeName}</span>`;
}
const pluginToFeature = {
  image: ["IMAGE"],
  gallery: ["GALLERY"],
  poll: ["POLL"],
  divider: ["DIVIDER"],
  video: ["VIDEO"],
  audio: ["AUDIO"],
  html: ["HTML"],
  toc: ["TOC"],
  table: ["TABLE"],
  collapsibleList: ["COLLAPSIBLE_LIST"],
  appEmbed: ["APP_EMBED"],
  codeBlock: ["CODE_BLOCK"],
  giphy: ["GIF"],
  file: ["FILE"],
  actionButton: ["BUTTON"],
  linkButton: ["BUTTON"],
  linkPreview: ["LINK_PREVIEW", "EMBED"],
  link: ["LINK"],
  textColor: ["COLOR_DECORATION"],
  textHighlight: ["COLOR_DECORATION", "SKETCH_DECORATION"],
  shape: ["SHAPE"],
  spoiler: ["SPOILER"],
  mention: ["MENTION"],
  hashtag: [],
  headings: [],
  emoji: [],
  indent: [],
  lineSpacing: ["LINE_SPACING"],
  ai: []
};
const getPluginsByFeatures = (feature) => {
  if (!feature) {
    return [];
  }
  return Object.keys(pluginToFeature).filter(
    (pluginName) => pluginToFeature[pluginName].some((f) => feature.includes(f))
  );
};
const ITEMS_FORCED_TO_MENU = ["NodeStyle", "TextStyle", "Link", "FileSource", "Media"];
export {
  collectUsedBy,
  jtdToMd
};
//# sourceMappingURL=jtd-to-md.js.map
