import { createSupabaseServiceRoleClient } from "@/lib/supabase/service-role"; import { fetchUnsplashWallpaperPhotos, type UnsplashPhoto, } from "@/server/api/unsplash"; import { getGalleryColorFamily } from "@/server/gallery/color"; const SOURCE = "unsplash-wallpapers"; const DEFAULT_PAGE = 1; const DEFAULT_PER_PAGE = 20; type GallerySyncState = { source: string; next_page: number; per_page: number; }; type GalleryPhotoRow = { unsplash_id: string; slug: string | null; description: string | null; alt_description: string | null; width: number | null; height: number | null; color: string | null; color_family: string | null; blur_hash: string | null; likes: number | null; photo_created_at: string | null; photo_updated_at: string | null; urls: Record; links: Record; user_info: Record; raw: Record; source: string; }; function normalizeDate(value: string | null | undefined) { if (!value) { return null; } const date = new Date(value); return Number.isNaN(date.getTime()) ? null : date.toISOString(); } function mapPhotoToRow(photo: UnsplashPhoto): GalleryPhotoRow { const raw = photo as Record; return { unsplash_id: photo.id, slug: photo.slug ?? null, description: photo.description ?? null, alt_description: photo.alt_description ?? null, width: photo.width ?? null, height: photo.height ?? null, color: photo.color ?? null, color_family: getGalleryColorFamily(photo.color), blur_hash: photo.blur_hash ?? null, likes: photo.likes ?? null, photo_created_at: normalizeDate(photo.created_at), photo_updated_at: normalizeDate(photo.updated_at), urls: photo.urls ?? {}, links: photo.links ?? {}, user_info: photo.user ?? {}, raw, source: SOURCE, }; } async function getSyncState() { const supabase = createSupabaseServiceRoleClient(); const { data, error } = await supabase .from("wg_gallery_sync_state") .select("source,next_page,per_page") .eq("source", SOURCE) .maybeSingle(); if (error) { throw error; } if (data) { return { supabase, state: data, }; } const initialState = { source: SOURCE, next_page: DEFAULT_PAGE, per_page: DEFAULT_PER_PAGE, }; const { error: insertError } = await supabase .from("wg_gallery_sync_state") .insert(initialState); if (insertError) { throw insertError; } return { supabase, state: initialState, }; } export async function syncUnsplashWallpapersToGallery() { const { supabase, state } = await getSyncState(); const page = state.next_page || DEFAULT_PAGE; const perPage = state.per_page || DEFAULT_PER_PAGE; try { const photos = await fetchUnsplashWallpaperPhotos({ page, perPage }); const rows = photos.map(mapPhotoToRow); let insertedCount = 0; if (rows.length > 0) { const { data, error } = await supabase .from("wg_gallery_photos") .upsert(rows, { onConflict: "unsplash_id", ignoreDuplicates: true, }) .select("unsplash_id"); if (error) { throw error; } insertedCount = data?.length ?? 0; } const nextPage = rows.length === 0 ? DEFAULT_PAGE : page + 1; const { error: updateError } = await supabase .from("wg_gallery_sync_state") .upsert( { source: SOURCE, next_page: nextPage, per_page: perPage, last_synced_at: new Date().toISOString(), last_inserted_count: insertedCount, last_seen_count: photos.length, last_error: null, }, { onConflict: "source" }, ); if (updateError) { throw updateError; } return { source: SOURCE, page, nextPage, seenCount: photos.length, insertedCount, }; } catch (error) { const message = error instanceof Error ? error.message : "Unknown sync error."; await supabase.from("wg_gallery_sync_state").upsert( { source: SOURCE, next_page: page, per_page: perPage, last_synced_at: new Date().toISOString(), last_inserted_count: 0, last_seen_count: 0, last_error: message, }, { onConflict: "source" }, ); throw error; } }