import type { PreviewImage } from './ImagePreviewDialog';

const PREVIEWABLE_IMAGE_EXTENSIONS = new Set([
  'png',
  'jpg',
  'jpeg',
  'gif',
  'bmp',
  'svg',
  'webp',
  'tif',
  'tiff',
]);

export function getFileExtension(value: string): string {
  if (typeof value !== 'string' || value === '') {
    return '';
  }
  const cleanValue = value.split('?')[0].split('#')[0];
  return cleanValue.split('.').pop()?.toLowerCase() ?? '';
}

export function isPreviewableImageFileName(fileName: string): boolean {
  return PREVIEWABLE_IMAGE_EXTENSIONS.has(getFileExtension(fileName));
}

const NON_IMAGE_EXTENSIONS = new Set([
  'pdf',
  'mp4',
  'avi',
  'mov',
  'mkv',
  'doc',
  'docx',
  'xls',
  'xlsx',
  'zip',
]);

export function normalizeHref(href: unknown): string {
  if (typeof href !== 'string' || href === '') {
    return '';
  }
  try {
    if (typeof window === 'undefined' || typeof window.location?.origin !== 'string') {
      return href;
    }
    return new URL(href, window.location.origin).toString();
  } catch (error) {
    return href;
  }
}

export function findPreviewIndexByHref(
  images: PreviewImage[],
  href: string,
): number {
  const normalizedHref = normalizeHref(href);
  return images.findIndex((image) => image.src === normalizedHref);
}

export function setPreviewHoverCursor(
  target: HTMLElement | null,
  images: PreviewImage[],
  defaultCursor = 'pointer',
): void {
  const link = target?.closest('a');
  if (!link) {
    return;
  }

  const href = link.getAttribute('href') ?? '';
  const isPreviewLink = findPreviewIndexByHref(images, href) >= 0;
  const cursor = isPreviewLink ? 'zoom-in' : defaultCursor;

  link.style.cursor = cursor;
  const image = link.querySelector('img');
  if (image != null) {
    image.style.cursor = cursor;
  }
}

function isLikelyImageHref(href: string): boolean {
  const normalized = normalizeHref(href);
  if (normalized === '') {
    return false;
  }

  const extension = getFileExtension(normalized);
  if (extension !== '') {
    if (PREVIEWABLE_IMAGE_EXTENSIONS.has(extension)) {
      return true;
    }
    if (NON_IMAGE_EXTENSIONS.has(extension)) {
      return false;
    }
  }

  // Handle endpoints that serve images without an explicit extension.
  if (normalized.includes('/api/image/') || normalized.includes('/image/')) {
    return true;
  }

  // Heuristic for /api/file/... links that are known image derivatives.
  if (normalized.includes('/api/file/')) {
    return normalized.includes('/mark') || normalized.includes('/public/');
  }

  return false;
}

function extractLinksFromHtml(html: string): string[] {
  if (typeof window !== 'undefined' && typeof DOMParser !== 'undefined') {
    try {
      const doc = new DOMParser().parseFromString(html, 'text/html');
      return Array.from(doc.querySelectorAll('a[href]'))
        .map((anchor) => anchor.getAttribute('href') ?? '')
        .filter((href) => href !== '');
    } catch (error) {
      // fall back to regex below
    }
  }

  const linkRegex = /<a[^>]+href=(['"])(.*?)\1/gi;
  const hrefs: string[] = [];
  let match: RegExpExecArray | null = linkRegex.exec(html);
  while (match != null) {
    hrefs.push(match[2]);
    match = linkRegex.exec(html);
  }
  return hrefs;
}

export function extractPreviewImagesFromHtml(html: string): PreviewImage[] {
  if (html === '') {
    return [];
  }

  const hrefs = extractLinksFromHtml(html);

  const uniqueImageHrefs = Array.from(
    new Set(
      hrefs
        .map((href) => normalizeHref(href))
        .filter((href) => isLikelyImageHref(href)),
    ),
  );

  return uniqueImageHrefs.map((href, index) => ({
    id: index,
    src: href,
    alt: `Bild ${index + 1}`,
  }));
}

type PreviewItemMapper<T> = {
  getId: (item: T) => number;
  getSrc: (item: T) => string;
  getFileName: (item: T) => unknown;
  getAlt?: (item: T) => string;
};

export function mapPreviewImagesFromItems<T>(
  items: T[],
  mapper: PreviewItemMapper<T>,
): PreviewImage[] {
  return items
    .filter((item) => isLikelyImageHref(String(mapper.getFileName(item) ?? '')))
    .map((item) => ({
      id: mapper.getId(item),
      src: mapper.getSrc(item),
      alt: mapper.getAlt?.(item) ?? String(mapper.getFileName(item) ?? ''),
    }));
}
