import type { GalleryAd } from '@/types/gallery-ads';

export type GridItem<T = any> =
  | { type: 'video'; data: T }
  | { type: 'photo'; data: any }
  | { type: 'album'; data: any }
  | { type: 'ad'; data: GalleryAd };

/**
 * Merge ads into a video grid based on each ad's frequency setting.
 *
 * Algorithm:
 * 1. Build a map of desired insertion slots for each ad
 *    (ad with frequency N inserts after every Nth video: positions N-1, 2N-1, 3N-1, ...)
 * 2. Resolve collisions: higher priority (lower position number) wins the slot,
 *    lower-priority ads shift to the next available slot
 * 3. Return merged array with videos and ads interleaved
 */
export function mergeAdsIntoGrid<T extends { id: number }>(
  videos: T[],
  ads: GalleryAd[]
): GridItem<T>[] {
  if (ads.length === 0) {
    return videos.map((v) => ({ type: 'video' as const, data: v }));
  }

  // Sort ads by position (priority) — lower position = higher priority
  const sortedAds = [...ads].sort((a, b) => (a.position ?? 0) - (b.position ?? 0));

  // Calculate target slots for each ad
  // slot index is in "video-only" space (0-indexed)
  const slotAssignments = new Map<number, GalleryAd>();
  const usedSlots = new Set<number>();

  for (const ad of sortedAds) {
    const freq = ad.frequency;
    // Insert after every freq-th video: at indices freq-1, 2*freq-1, etc.
    for (let i = freq - 1; i < videos.length; i += freq) {
      let targetSlot = i;

      // If slot is taken, find next available
      while (usedSlots.has(targetSlot) && targetSlot < videos.length + ads.length) {
        targetSlot++;
      }

      if (!usedSlots.has(targetSlot)) {
        slotAssignments.set(targetSlot, ad);
        usedSlots.add(targetSlot);
        break; // Each ad appears at most once per page
      }
    }
  }

  // Build merged array
  const result: GridItem<T>[] = [];
  let videoIdx = 0;

  for (let pos = 0; videoIdx < videos.length || slotAssignments.has(pos); pos++) {
    const adForSlot = slotAssignments.get(pos);
    if (adForSlot) {
      const adItem: GridItem<T> = { type: 'ad', data: adForSlot };
      result.push(adItem);
    }

    if (videoIdx < videos.length) {
      result.push({ type: 'video', data: videos[videoIdx]! });
      videoIdx++;
    }
  }

  return result;
}

/**
 * Merge ads into a unified media grid (videos + photos + albums).
 */
export function mergeAdsIntoMediaGrid(
  items: Array<{ type: 'video' | 'photo' | 'album'; data: any }>,
  ads: GalleryAd[]
): GridItem[] {
  if (ads.length === 0) {
    return items;
  }

  const sortedAds = [...ads].sort((a, b) => (a.position ?? 0) - (b.position ?? 0));
  const slotAssignments = new Map<number, GalleryAd>();
  const usedSlots = new Set<number>();

  for (const ad of sortedAds) {
    const freq = ad.frequency;
    for (let i = freq - 1; i < items.length; i += freq) {
      let targetSlot = i;
      while (usedSlots.has(targetSlot) && targetSlot < items.length + ads.length) {
        targetSlot++;
      }
      if (!usedSlots.has(targetSlot)) {
        slotAssignments.set(targetSlot, ad);
        usedSlots.add(targetSlot);
        break;
      }
    }
  }

  const result: GridItem[] = [];
  let itemIdx = 0;

  for (let pos = 0; itemIdx < items.length || slotAssignments.has(pos); pos++) {
    const adForSlot = slotAssignments.get(pos);
    if (adForSlot) {
      result.push({ type: 'ad', data: adForSlot });
    }
    if (itemIdx < items.length) {
      result.push(items[itemIdx]!);
      itemIdx++;
    }
  }

  return result;
}
