import type { Story } from '@/types/story';

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

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

export 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);
};

export 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);
};

export 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 collectCriticalStoryUrls(
    stories: Story[],
    selectedStoryId?: number | null,
    criticalCount = 3,
    extraUrls?: string[]
): string[] {
    const typedStories = stories as StoryWithMedia[];
    const set = new Set<string>();

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

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

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

    extraUrls?.forEach((url) => {
        if (url) set.add(url);
    });

    return [...set];
}

function preloadOne(src: string): Promise<void> {
    return new Promise<void>((resolve) => {
        const img = new Image();
        img.onload = async () => {
            try {
                await img.decode?.();
            } catch {
                // ignore decode errors — the image is loaded enough to use
            }
            resolve();
        };
        img.onerror = () => resolve();
        img.src = src;
    });
}

export async function preloadImagesPromise(urls: string[], timeoutMs = 8000): Promise<void> {
    if (!urls.length) return;
    await Promise.race([
        Promise.all(urls.map(preloadOne)).then(() => undefined),
        new Promise<void>((resolve) => setTimeout(resolve, timeoutMs)),
    ]);
}
