import type { Article, Category, CategorySection, Order, Page, Product, ProductDetailSection, StoreSettings } from '@homaroma/types' import { API_BASE } from './api' const isDev = process.env.NODE_ENV === 'development' const defaultRevalidate = 0 type ProductListResponse = { data?: Product[] } export type Coupon = { id: number code: string type: 'PERCENTAGE' | 'FIXED_AMOUNT' | 'FREE_SHIPPING' | string value: number minPurchase: number usageLimit: number | null usedCount: number expiresAt?: string | null } export type ProductReview = { id: number rating: number comment?: string | null customerName?: string | null createdAt: string customer?: { displayName?: string | null pictureUrl?: string | null } | null } export type ApiResult = | { ok: true; data: T } | { ok: false; error: string; status?: number } export async function fetchJson(path: string, init?: RequestInit & { next?: { revalidate?: number } }): Promise { try { const res = await fetch(`${API_BASE}${path}`, { cache: 'no-store', ...init, next: init?.next ?? { revalidate: 0 }, }) if (!res.ok) { console.error(`[website-api] ${path} returned ${res.status}`) return null } return await res.json() as T } catch (error) { console.error(`[website-api] Failed to fetch ${path}`, error) return null } } export async function fetchJsonResult(path: string, init?: RequestInit & { next?: { revalidate?: number } }): Promise> { try { const res = await fetch(`${API_BASE}${path}`, { cache: 'no-store', ...init, next: init?.next ?? { revalidate: 0 }, }) if (!res.ok) { return { ok: false, error: `${path} returned ${res.status}`, status: res.status } } return { ok: true, data: await res.json() as T } } catch (error) { return { ok: false, error: error instanceof Error ? error.message : `Failed to fetch ${path}`, } } } export async function getCategories(lang = 'all'): Promise { return await fetchJson(`/categories?lang=${lang}`, { next: { revalidate: 0 } }) ?? [] } export async function getCategoriesResult(lang = 'all'): Promise> { return await fetchJsonResult(`/categories?lang=${lang}`, { next: { revalidate: 0 } }) } export async function getStoreSettings(lang = 'all'): Promise { return await fetchJson(`/settings?lang=${lang}`, { next: { revalidate: defaultRevalidate } }) } export async function getStoreSettingsResult(lang = 'all'): Promise> { return await fetchJsonResult(`/settings?lang=${lang}`, { next: { revalidate: defaultRevalidate } }) } export async function getCmsPage(slug: string, lang = 'all'): Promise { return await fetchJson(`/pages/${slug}?lang=${lang}`, { next: { revalidate: defaultRevalidate } }) } export async function getCmsPageResult(slug: string, lang = 'all'): Promise> { return await fetchJsonResult(`/pages/${slug}?lang=${lang}`, { next: { revalidate: defaultRevalidate } }) } export async function getArticlesResult(): Promise> { return await fetchJsonResult('/articles?publishedOnly=true', { next: { revalidate: defaultRevalidate } }) } export async function getActiveCouponsResult(): Promise> { const response = await fetchJsonResult('/coupons/active', { next: { revalidate: defaultRevalidate } }) if (!response.ok) return response return { ok: true, data: response.data.filter((coupon) => coupon.usageLimit === null || coupon.usedCount < coupon.usageLimit), } } export async function getOrderResult(id: string | number, lang = 'all'): Promise> { const query = lang && lang !== 'all' ? `?lang=${lang}` : '' return await fetchJsonResult(`/orders/${id}${query}`, { next: { revalidate: defaultRevalidate } }) } export async function getProduct(id: string | number, lang = 'all'): Promise { return await fetchJson(`/products/${id}?lang=${lang}`, { next: { revalidate: defaultRevalidate } }) } export async function getProductResult(id: string | number, lang = 'all'): Promise> { return await fetchJsonResult(`/products/${id}?lang=${lang}`, { next: { revalidate: defaultRevalidate } }) } export async function getProductDetailSectionsResult(id: string | number, lang = 'all'): Promise> { return await fetchJsonResult(`/products/${id}/detail-sections?lang=${lang}`, { next: { revalidate: defaultRevalidate } }) } export async function getCategorySectionsResult(id: string | number, lang = 'all'): Promise> { return await fetchJsonResult(`/categories/${id}/sections?lang=${lang}`, { next: { revalidate: defaultRevalidate } }) } export async function getProductReviewsResult(id: string | number): Promise> { return await fetchJsonResult(`/reviews/product/${id}`, { next: { revalidate: defaultRevalidate } }) } export async function getProducts(query = '', lang = 'all'): Promise { const separator = query ? '&' : '' const response = await fetchJson(`/products?${query}${separator}lang=${lang}`, { next: { revalidate: defaultRevalidate }, }) return response?.data ?? [] } export async function getProductsResult(query = '', lang = 'all'): Promise> { const separator = query ? '&' : '' const response = await fetchJsonResult(`/products?${query}${separator}lang=${lang}`, { next: { revalidate: defaultRevalidate }, }) if (!response.ok) return response return { ok: true, data: response.data.data ?? [] } }