export interface ParagraphDescriptor {
  element: HTMLParagraphElement;
  key: string;
  excerpt: string;
  normalizedText: string;
}

export function normalizeParagraphText(text: string): string {
  return text.replace(/\s+/g, ' ').trim().toLowerCase();
}

export function createParagraphExcerpt(text: string, limit = 120): string {
  const flattened = text.replace(/\s+/g, ' ').trim();
  if (flattened.length <= limit) {
    return flattened;
  }

  return `${flattened.slice(0, limit).trimEnd()}...`;
}

export function fnv1aHash(value: string): string {
  let hash = 0x811c9dc5;

  for (let index = 0; index < value.length; index += 1) {
    hash ^= value.charCodeAt(index);
    hash = Math.imul(hash, 0x01000193);
  }

  return (hash >>> 0).toString(16).padStart(8, '0');
}

export function buildParagraphDescriptors(container: HTMLElement): ParagraphDescriptor[] {
  const occurrences = new Map<string, number>();
  const paragraphs = Array.from(container.querySelectorAll('p')).filter(
    child => child instanceof HTMLParagraphElement
  ) as HTMLParagraphElement[];

  return paragraphs
    .map(element => {
      const normalizedText = normalizeParagraphText(element.textContent || '');
      if (!normalizedText) {
        return null;
      }

      const hash = fnv1aHash(normalizedText);
      const nextOccurrence = (occurrences.get(hash) || 0) + 1;
      occurrences.set(hash, nextOccurrence);

      return {
        element,
        key: `p-${hash}-${nextOccurrence}`,
        excerpt: createParagraphExcerpt(element.textContent || ''),
        normalizedText,
      };
    })
    .filter((item): item is ParagraphDescriptor => Boolean(item));
}
