import { AlbumNotFoundException } from "../exceptions";
import type { Album } from "../interfaces";
import { getAlbum } from "./getAlbum";
import { getPhotos } from "./getPhotos";

export const extractAlbum = async (albumUrl: string): Promise<Album> => {
	const gAlbum = await getAlbum(albumUrl);
	if (!gAlbum) throw new AlbumNotFoundException();

	const { items, key, id, title, cover, createdAt, updatedAt } = gAlbum;

	// Optimized O(1) Lookup Map
	const itemsMap = new Map(items.map((item) => [item.id, item.url]));

	const album: Album = {
		id,
		title,
		url: albumUrl,
		photos: [],
		createdAt,
		updatedAt,
	};

	const { default: pLimit } = await import("p-limit");
	const MAX_CONCURRENT_REQUESTS = 5;
	const limit = pLimit(MAX_CONCURRENT_REQUESTS);

	const chunkSize = 500; // Optimal batch size for Google Photos RPC
	const tasks = [];

	for (let i = 0; i < items.length; i += chunkSize) {
		tasks.push(
			limit(async () => {
				const chunk = items.slice(i, i + chunkSize);
				const ids = chunk.map((el) => el.id);

				try {
					const photosInfo = await getPhotos(key, ids);
					return photosInfo.map((el) => {
						const url = itemsMap.get(el.id) || "";
						return { ...el, url };
					});
				} catch (err) {
					console.error(`Failed to fetch chunk starting at index ${i}`, err);
					return []; // Fail gracefully for this chunk
				}
			}),
		);
	}

	const results = await Promise.all(tasks);
	album.photos.push(...results.flat());

	// Sorting descending by createdAt
	album.photos.sort((a, b) => b.createdAt - a.createdAt);

	if (cover) {
		album.cover = album.photos.find((photo) => photo.url === cover.url);
	}

	return album;
};
