import { removeHtmlTags } from '@/utils/creatorHelpers';

const PDF_FILE_PREFIX = 'azopus.hu';

export type PdfTextSegment = {
  isBold?: boolean;
  text: string;
};

const decodePdfText = (value: string): string =>
  value
    .replace(/&nbsp;/g, ' ')
    .replace(/&amp;/g, '&')
    .replace(/&lt;/g, '<')
    .replace(/&gt;/g, '>')
    .replace(/&quot;/g, '"')
    .replace(/&#39;/g, "'")
    .replace(/&apos;/g, "'")
    .replace(/\u00a0/g, ' ');

const normalizePdfInlineWhitespace = (value: string): string =>
  value.replace(/[ \t\f\v]+/g, ' ').replace(/ *\n */g, '\n');

export const normalizePdfText = (value?: string | null): string =>
  removeHtmlTags((value ?? '').replaceAll('|', ', ').replaceAll('<0xa0>', ' '))
    .replace(/\u00a0/g, ' ')
    .replace(/\s+/g, ' ')
    .trim();

export const htmlToPdfParagraphs = (html?: string | null): string[] => {
  if (!html) return [];

  return htmlToPdfParagraphSegments(html).map((segments) =>
    segments
      .map((segment) => segment.text)
      .join('')
      .trim()
  );
};

const mergeAdjacentSegments = (segments: PdfTextSegment[]): PdfTextSegment[] =>
  segments.reduce<PdfTextSegment[]>((acc, segment) => {
    if (!segment.text) return acc;

    const previous = acc[acc.length - 1];
    if (previous && Boolean(previous.isBold) === Boolean(segment.isBold)) {
      previous.text += segment.text;
      return acc;
    }

    acc.push(segment);
    return acc;
  }, []);

const htmlBlockToPdfTextSegments = (htmlBlock: string): PdfTextSegment[] => {
  const segments: PdfTextSegment[] = [];
  const tagRegex = /<\/?[^>]+>/g;
  let boldDepth = 0;
  let lastIndex = 0;
  let match: RegExpExecArray | null;

  const pushText = (value: string) => {
    const text = decodePdfText(value);
    if (text) {
      segments.push({
        isBold: boldDepth > 0,
        text,
      });
    }
  };

  while ((match = tagRegex.exec(htmlBlock))) {
    pushText(htmlBlock.slice(lastIndex, match.index));

    const tag = match[0].toLowerCase();
    const tagName = tag.match(/^<\/?\s*([a-z0-9]+)/)?.[1];
    const isClosingTag = /^<\//.test(tag);

    if (tagName === 'b' || tagName === 'strong') {
      boldDepth = isClosingTag ? Math.max(0, boldDepth - 1) : boldDepth + 1;
    }

    lastIndex = tagRegex.lastIndex;
  }

  pushText(htmlBlock.slice(lastIndex));

  return mergeAdjacentSegments(segments);
};

export const htmlToPdfParagraphSegments = (html?: string | null): PdfTextSegment[][] => {
  if (!html) return [];

  const withBreaks = html
    .replace(/\r\n/g, '\n')
    .replace(/<br\s*\/?>/gi, '\n')
    .replace(/<\/p>/gi, '\n\n')
    .replace(/<\/(div|h[1-6]|li)>/gi, '\n')
    .replace(/<li[^>]*>/gi, '- ')
    .replace(/<\/?p[^>]*>/gi, '')
    .replace(/<0xa0>/g, ' ');

  return withBreaks
    .split(/\n{2,}/)
    .map((block) => normalizePdfInlineWhitespace(block).trim())
    .map(htmlBlockToPdfTextSegments)
    .map((segments) =>
      segments.map((segment) => ({
        ...segment,
        text: normalizePdfInlineWhitespace(segment.text),
      }))
    )
    .filter((segments) => segments.some((segment) => segment.text.trim()));
};

export const slugifyPdfFileNamePart = (value?: string | null): string =>
  normalizePdfText(value)
    .toLowerCase()
    .normalize('NFD')
    .replace(/[\u0300-\u036f]/g, '')
    .replace(/[^a-z0-9\s-]/g, '')
    .trim()
    .replace(/\s+/g, '-');

export const createPdfFileName = (...parts: Array<string | null | undefined>): string => {
  const slug = parts.map(slugifyPdfFileNamePart).filter(Boolean).join('-') || 'document';

  return `${PDF_FILE_PREFIX}-${slug}.pdf`;
};
