import { useMemo } from 'react';
import { useImagePreloader } from './useImagePreloader';
import type { Story } from '@/types/story';

interface StoryMediaLike {
  type: 'image' | 'audio';
  filename: string;
  path: string;
}

interface StoryWithMedia extends Omit<Story, 'media'> {
  media?: StoryMediaLike[] | StoryMediaLike;
}

interface UseStoryLibraryPreloaderOptions {
  critical?: number;
  selectedStoryId?: number | null;
  extraCriticalUrls?: string[];
  timeout?: number;
  retries?: number;
}

const isGradient = (value?: string) =>
  !!value && (value.startsWith('linear-gradient') || value.startsWith('radial-gradient'));

const addUrl = (set: Set<string>, url?: string) => {
  if (url && !isGradient(url)) set.add(url);
};

const collectStoryImages = (story: StoryWithMedia, into: Set<string>) => {
  addUrl(into, story.background);
  addUrl(into, story.background_image_url);
  if (story.thumbnail_url) into.add(story.thumbnail_url);
  if (story.library_image) into.add(story.library_image);
};

const findDefaultMedia = (story: StoryWithMedia): string | undefined => {
  const media = Array.isArray(story.media) ? story.media : undefined;
  return media?.find((m) => m.type === 'image' && m.filename?.toLowerCase() === 'default.webp')
    ?.path;
};

export function useStoryLibraryPreloader(
  stories: Story[],
  options: UseStoryLibraryPreloaderOptions = {}
) {
  const {
    critical = 3,
    selectedStoryId = null,
    extraCriticalUrls,
    timeout = 10000,
    retries = 2,
  } = options;

  const extraKey = useMemo(
    () => (extraCriticalUrls ? [...extraCriticalUrls].sort().join('|') : ''),
    [extraCriticalUrls]
  );

  const { criticalUrls, remainingUrls } = useMemo(() => {
    const typedStories = stories as StoryWithMedia[];
    const criticalSet = new Set<string>();
    const remainingSet = new Set<string>();

    const initialStory = selectedStoryId
      ? (typedStories.find((s) => s.id === selectedStoryId) ?? typedStories[0])
      : typedStories[0];

    if (initialStory) {
      collectStoryImages(initialStory, criticalSet);
      const defaultMedia = findDefaultMedia(initialStory);
      if (defaultMedia) criticalSet.add(defaultMedia);
    }

    typedStories.slice(0, critical).forEach((story) => {
      collectStoryImages(story, criticalSet);
      const defaultMedia = findDefaultMedia(story);
      if (defaultMedia) criticalSet.add(defaultMedia);
    });
    typedStories.slice(critical).forEach((story) => collectStoryImages(story, remainingSet));

    extraCriticalUrls?.forEach((url) => url && criticalSet.add(url));

    return {
      criticalUrls: [...criticalSet],
      remainingUrls: [...remainingSet].filter((url) => !criticalSet.has(url)),
    };
    // extraCriticalUrls is tracked via extraKey so inline arrays don't churn memoization
    // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [stories, critical, selectedStoryId, extraKey]);

  const { isComplete: criticalReady } = useImagePreloader(criticalUrls, {
    priority: criticalUrls,
    timeout,
    retries,
  });

  const { isComplete: remainingReady } = useImagePreloader(remainingUrls, {
    timeout,
    retries: 1,
  });

  return {
    criticalReady,
    allReady: criticalReady && remainingReady,
    criticalUrls,
    remainingUrls,
  };
}
