import type { ImageSource, Slide } from 'yet-another-react-lightbox';

import {
  type ImageMetaLabels,
  type ImageSize,
  buildImageMetaText,
  buildMediaUrl,
} from '@/utils/images';

import type { ImageObject } from '@/types/Common';

export type AppLightboxSlide = Slide & {
  sourceImage?: ImageObject;
  videoId?: string;
  videoSource?: string | null;
  videoRightsHolder?: string | null;
};

interface CreationImageSlideOptions {
  fallbackTitle?: string;
  labels: ImageMetaLabels;
  optimizeImages?: boolean;
}

interface VideoSlideInput {
  id: string;
  title?: string | null;
  source?: string | null;
  rightsHolder?: string | null;
}

interface VideoSlideOptions {
  sourceLabel?: string;
  rightsHolderLabel?: string;
}

// Az inline carousel a előre generált szélesség-variánsokból kap srcSet-et.
// A descriptor-szélességet az eredetihez vágjuk (a generálás withoutEnlargement),
// és dedupeoljuk, ha kis eredetinél több variáns ugyanarra a méretre esik.
const INLINE_WIDTHS: ImageSize[] = ['w640', 'w1024', 'w1920'];

const widthOfSize = (size: ImageSize) => Number(size.replace(/\D/g, ''));

function buildInlineSrcSet(
  id: string | number,
  width?: number,
  height?: number
): ImageSource[] | undefined {
  if (!width || !height || width <= 0 || height <= 0) return undefined;

  const sources = INLINE_WIDTHS.map((size) => {
    const w = Math.min(widthOfSize(size), width);
    return {
      src: buildMediaUrl(id, size),
      width: w,
      height: Math.round((w * height) / width),
    };
  }).filter((s, i, arr) => arr.findIndex((x) => x.width === s.width) === i);

  return sources.length > 0 ? sources : undefined;
}

export function getYoutubeId(input: string): string | null {
  if (!input) return null;

  if (input.length === 11 && !/[\/=&?]/.test(input)) {
    return input;
  }

  const patterns = [
    /(?:youtube\.com\/watch\?v=|youtu\.be\/|youtube\.com\/embed\/)([a-zA-Z0-9_-]{11})/,
    /youtube\.com\/watch\?.*v=([a-zA-Z0-9_-]{11})/,
    /youtu\.be\/([a-zA-Z0-9_-]{11})/,
  ];

  for (const pattern of patterns) {
    const match = input.match(pattern);
    if (match?.[1]) return match[1];
  }

  return null;
}

export function getYoutubeThumbnail(input: string): string {
  const videoId = getYoutubeId(input) ?? input;
  return `https://img.youtube.com/vi/${videoId}/hqdefault.jpg`;
}

export function mapCreationImagesToLightboxSlides(
  images: ImageObject[],
  options: CreationImageSlideOptions
): AppLightboxSlide[] {
  return images.map((image) => {
    const caption = image.kepalairas?.trim();
    const alt = caption || options.fallbackTitle || '';
    // A fullscreen a legnagyobb variánst kapja. Az inline carousel ehhez srcSet-et is.
    const fullSrc = buildMediaUrl(image.id, 'w1920');
    const slideImage = options.optimizeImages
      ? { src: fullSrc, srcSet: buildInlineSrcSet(image.id, image.width, image.height) }
      : { src: fullSrc };

    return {
      ...slideImage,
      alt,
      width: image.width,
      height: image.height,
      imageFit: 'contain',
      title: caption || options.fallbackTitle,
      description: buildImageMetaText(image, false, options.labels),
      thumbnail: buildMediaUrl(image.id, 'w256'),
      sourceImage: image,
    };
  });
}

export function buildVideoLightboxSlide(
  video: VideoSlideInput,
  options: VideoSlideOptions = {}
): AppLightboxSlide | null {
  const videoId = getYoutubeId(video.id);
  if (!videoId) return null;

  const source = video.source?.trim();
  const rightsHolder = video.rightsHolder?.trim();

  const descriptionLines = [
    source && options.sourceLabel ? `${options.sourceLabel}: ${source}` : null,
    rightsHolder && options.rightsHolderLabel
      ? `${options.rightsHolderLabel}: ${rightsHolder}`
      : null,
  ].filter(Boolean);

  return {
    src: getYoutubeThumbnail(videoId),
    alt: video.title || '',
    width: 1280,
    height: 720,
    title: video.title || undefined,
    description: descriptionLines.length > 0 ? descriptionLines.join('\n') : undefined,
    thumbnail: getYoutubeThumbnail(videoId),
    videoId,
    videoSource: video.source,
    videoRightsHolder: video.rightsHolder,
  };
}
