import TurndownService from "turndown";
import { detectCodeLanguage } from "./lang-hints.js";
function longestBacktickRun(s) {
  let max = 0;
  let cur = 0;
  for (let i = 0; i < s.length; i++) {
    if (s.charCodeAt(i) === 96) {
      cur++;
      if (cur > max) max = cur;
    } else {
      cur = 0;
    }
  }
  return max;
}
function buildTurndown() {
  const td = new TurndownService({ headingStyle: "atx", codeBlockStyle: "fenced" });
  td.remove(["script", "style"]);
  td.addRule("table", {
    filter: "table",
    replacement(_content, node) {
      const el = node;
      const rows = Array.from(el.querySelectorAll("tr"));
      if (rows.length === 0) return "";
      const renderRow = (row) => {
        const cells = Array.from(row.querySelectorAll("th, td"));
        return "| " + cells.map((c) => c.textContent?.replace(/\n/g, " ").trim() ?? "").join(" | ") + " |";
      };
      const headerRow = rows[0];
      const isHeaderRow = headerRow.querySelectorAll("th").length > 0;
      const headerCells = Array.from(headerRow.querySelectorAll("th, td"));
      const separator = "| " + headerCells.map(() => "---").join(" | ") + " |";
      if (isHeaderRow) {
        const bodyRows = rows.slice(1);
        const lines2 = [renderRow(headerRow), separator, ...bodyRows.map(renderRow)];
        return "\n\n" + lines2.join("\n") + "\n\n";
      }
      const lines = [renderRow(headerRow), separator, ...rows.slice(1).map(renderRow)];
      return "\n\n" + lines.join("\n") + "\n\n";
    }
  });
  td.addRule("tableCell", {
    filter: ["thead", "tbody", "tfoot", "tr", "th", "td"],
    replacement(content) {
      return content;
    }
  });
  td.addRule("codeBlockLang", {
    filter(node) {
      return node.nodeName === "PRE" && node.querySelector("code") !== null;
    },
    replacement(_content, node) {
      const pre = node;
      const code = pre.querySelector("code");
      const cls = code?.getAttribute("class") ?? pre.getAttribute("class") ?? "";
      const lang = detectCodeLanguage(cls);
      const body = code?.textContent ?? pre.textContent ?? "";
      const fence = "`".repeat(Math.max(3, longestBacktickRun(body) + 1));
      return `

${fence}${lang ?? ""}
${body.replace(/\n+$/, "")}
${fence}

`;
    }
  });
  return td;
}
const turndown = buildTurndown();
function htmlToMarkdown(html) {
  if (!html) return "";
  return turndown.turndown(html);
}
function parseHeadings(lines) {
  const headings = [];
  for (let i = 0; i < lines.length; i++) {
    const match = lines[i].match(/^(#{1,6})\s+(.+)/);
    if (match) {
      headings.push({ level: match[1].length, text: match[2].trim(), lineIndex: i });
    }
  }
  return headings;
}
function lineStartCharOffsets(lines) {
  const offsets = new Array(lines.length);
  let acc = 0;
  for (let i = 0; i < lines.length; i++) {
    offsets[i] = acc;
    acc += lines[i].length + 1;
  }
  return offsets;
}
function extractFromHeading(lines, headings, headingIdx) {
  const heading = headings[headingIdx];
  const start = heading.lineIndex;
  let end = lines.length;
  for (let i = headingIdx + 1; i < headings.length; i++) {
    if (headings[i].level <= heading.level) {
      end = headings[i].lineIndex;
      break;
    }
  }
  return lines.slice(start, end).join("\n");
}
function extractSection(markdown, section, sectionIndex = 0) {
  const lines = markdown.split("\n");
  const headings = parseHeadings(lines);
  if (headings.length === 0) return { content: markdown, matched: false };
  const lower = section.toLowerCase();
  const indexed = headings.map((h, i2) => ({ h, i: i2 }));
  const exactMatches = indexed.filter(({ h }) => h.text.toLowerCase() === lower);
  if (exactMatches.length > 0 && sectionIndex < exactMatches.length) {
    const { i: i2 } = exactMatches[sectionIndex];
    return { content: extractFromHeading(lines, headings, i2), matched: true };
  }
  const substringMatches = indexed.filter(({ h }) => h.text.toLowerCase().includes(lower));
  if (substringMatches.length === 0 || sectionIndex >= substringMatches.length) {
    return { content: markdown, matched: false };
  }
  const { i } = substringMatches[sectionIndex];
  return { content: extractFromHeading(lines, headings, i), matched: true };
}
function extractLinksAndImages(markdown) {
  const imagePattern = /!\[[^\]]*\]\(([^)]+)\)/g;
  const linkPattern = /(?<!!)\[[^\]]*\]\(([^)]+)\)/g;
  const images = /* @__PURE__ */ new Set();
  const links = /* @__PURE__ */ new Set();
  let match;
  while ((match = imagePattern.exec(markdown)) !== null) {
    images.add(match[1]);
  }
  while ((match = linkPattern.exec(markdown)) !== null) {
    links.add(match[1]);
  }
  return { links: Array.from(links), images: Array.from(images) };
}
const DECORATIVE_URL_MARKERS = [
  "avatar",
  "icon",
  "logo",
  "badge",
  "shield",
  "tracking",
  "pixel",
  "sprite",
  "emoji",
  "favicon"
];
function filterDecorativeImages(markdown) {
  if (!markdown) return markdown;
  return markdown.replace(/!\[([^\]]*)\]\(([^)]+)\)/g, (match, alt, src) => {
    const trimmedAlt = alt.trim();
    const lowerSrc = src.toLowerCase();
    if (lowerSrc.startsWith("data:image/gif;base64,")) return "";
    if (lowerSrc.startsWith("data:image/svg+xml") && src.length < 200) return "";
    for (const marker of DECORATIVE_URL_MARKERS) {
      if (lowerSrc.includes(marker)) return "";
    }
    if (!trimmedAlt) return "";
    return match;
  });
}
function resolveRelativeUrls(markdown, baseUrl) {
  if (!markdown || !baseUrl) return markdown;
  const rewrite = (path) => {
    const trimmed = path.trim();
    if (!trimmed) return path;
    if (/^(?:https?:|mailto:|tel:|javascript:|data:)/i.test(trimmed)) return path;
    if (trimmed.startsWith("#")) {
      try {
        return new URL(trimmed, baseUrl).href;
      } catch {
        return path;
      }
    }
    if (trimmed.startsWith("//")) {
      try {
        const base = new URL(baseUrl);
        return `${base.protocol}${trimmed}`;
      } catch {
        return path;
      }
    }
    try {
      return new URL(trimmed, baseUrl).href;
    } catch {
      return path;
    }
  };
  let result = markdown.replace(
    /(!\[[^\]]*\]\()([^)\s]+)(\s*(?:"[^"]*")?\))/g,
    (_m, open, path, close) => `${open}${rewrite(path)}${close}`
  );
  result = result.replace(
    /(^|[^!])(\[[^\]]*\]\()([^)\s]+)(\s*(?:"[^"]*")?\))/g,
    (_m, pre, open, path, close) => `${pre}${open}${rewrite(path)}${close}`
  );
  return result;
}
export {
  buildTurndown,
  extractLinksAndImages,
  extractSection,
  filterDecorativeImages,
  htmlToMarkdown,
  lineStartCharOffsets,
  parseHeadings,
  resolveRelativeUrls
};
//# sourceMappingURL=markdown.js.map