function normalizeTags(tags: string[]): string[] {
  const seen = new Set<string>();
  const result: string[] = [];
  for (const tag of tags) {
    const normalized = tag.trim();
    if (!normalized) continue;
    const key = normalized.toLowerCase();
    if (seen.has(key)) continue;
    seen.add(key);
    result.push(normalized);
  }
  return result;
}

function splitFrontmatter(content: string): {
  frontmatter: string | null;
  body: string;
} {
  const normalized = (content ?? "").replace(/\r\n/g, "\n");
  if (!normalized.startsWith("---\n")) {
    return { frontmatter: null, body: normalized };
  }

  const closingIndex = normalized.indexOf("\n---", 4);
  if (closingIndex === -1) {
    return { frontmatter: null, body: normalized };
  }

  const frontmatter = normalized.slice(4, closingIndex).trim();
  const bodyStart = closingIndex + "\n---".length;
  const body = normalized.slice(bodyStart).replace(/^\n/, "");
  return { frontmatter, body };
}

function parseTagsValue(rawValue: string): string[] {
  const value = rawValue.trim();
  if (!value) return [];

  if (value.startsWith("[") && value.endsWith("]")) {
    return normalizeTags(
      value
        .slice(1, -1)
        .split(",")
        .map((token) => token.trim().replace(/^["']|["']$/g, "")),
    );
  }

  return normalizeTags(
    value.split(",").map((token) => token.trim().replace(/^["']|["']$/g, "")),
  );
}

function formatTagsValue(tags: string[]): string {
  const normalized = normalizeTags(tags);
  if (!normalized.length) return "";
  return `[${normalized.join(", ")}]`;
}

export function parseTagsFromMarkdown(content: string): string[] {
  const { frontmatter } = splitFrontmatter(content);
  if (!frontmatter) return [];

  const line = frontmatter
    .split("\n")
    .find((entry) => /^\s*tags\s*:/i.test(entry));
  if (!line) return [];
  const value = line.replace(/^\s*tags\s*:/i, "");
  return parseTagsValue(value);
}

export function stripFrontmatter(content: string): string {
  return splitFrontmatter(content).body;
}

export function setTagsInMarkdown(content: string, tags: string[]): string {
  const normalizedBody = (content ?? "").replace(/\r\n/g, "\n");
  const normalizedTags = normalizeTags(tags);
  const tagsLine =
    normalizedTags.length > 0 ? `tags: ${formatTagsValue(normalizedTags)}` : "";
  const { frontmatter, body } = splitFrontmatter(normalizedBody);

  if (!frontmatter) {
    if (!tagsLine) return normalizedBody;
    const trimmedBody = body.replace(/^\n+/, "");
    return `---\n${tagsLine}\n---\n\n${trimmedBody}`;
  }

  const lines = frontmatter
    .split("\n")
    .map((line) => line.trimEnd())
    .filter((line) => !/^\s*tags\s*:/i.test(line));

  if (tagsLine) {
    lines.unshift(tagsLine);
  }

  if (lines.length === 0) {
    return body;
  }

  return `---\n${lines.join("\n")}\n---\n\n${body}`;
}

export function extractBracketTags(content: string): string[] {
  const normalized = (content ?? "").replace(/\r\n/g, "\n");
  const matches = normalized.matchAll(/\[\[([^\]]+)\]\]/g);
  const tokens: string[] = [];
  for (const match of matches) {
    const raw = (match[1] ?? "").trim();
    if (!raw) continue;
    tokens.push(
      ...raw
        .split(",")
        .map((token) => token.trim())
        .filter(Boolean),
    );
  }
  return normalizeTags(tokens);
}

export function extractTagsFromTagsSection(content: string): string[] {
  const normalized = (content ?? "").replace(/\r\n/g, "\n");
  const lines = normalized.split("\n");
  const collected: string[] = [];

  let inTagsSection = false;
  for (const rawLine of lines) {
    const line = rawLine.trim();
    if (!inTagsSection) {
      if (/^#{1,6}\s+tags\s*$/i.test(line)) {
        inTagsSection = true;
      }
      continue;
    }

    if (!line) break;
    if (/^#{1,6}\s+/.test(line)) break;

    const cleaned = line.replace(/^[-*+]\s+/, "");
    collected.push(
      ...cleaned
        .split(",")
        .map((token) => token.trim())
        .filter(Boolean),
    );
  }

  return normalizeTags(collected);
}

export function extractEntryTags(content: string): string[] {
  return normalizeTags([
    ...parseTagsFromMarkdown(content),
    ...extractBracketTags(content),
    ...extractTagsFromTagsSection(content),
  ]);
}
