"use client"

import { offlineStorage } from "./offline-storage"

interface FetchOptions extends RequestInit {
  // How long to cache the response (default: 1 hour)
  cacheTtl?: number
  // Cache key override (default: URL)
  cacheKey?: string
  // Skip cache and always fetch
  skipCache?: boolean
  // Return stale data while revalidating
  staleWhileRevalidate?: boolean
}

/**
 * Fetch wrapper that works offline using IndexedDB cache
 */
export async function offlineFetch<T = any>(
  url: string,
  options: FetchOptions = {}
): Promise<{ data: T; fromCache: boolean; isStale: boolean }> {
  const {
    cacheTtl = 60 * 60 * 1000, // 1 hour default
    cacheKey = url,
    skipCache = false,
    staleWhileRevalidate = true,
    ...fetchOptions
  } = options

  const isOnline = typeof navigator !== "undefined" ? navigator.onLine : true

  // Try to get cached data first
  let cachedData: { data: T; isStale: boolean } | null = null
  
  if (!skipCache && offlineStorage) {
    try {
      cachedData = await offlineStorage.getCachedApiResponse<T>(cacheKey)
    } catch (e) {
      console.warn("[offlineFetch] Cache read failed:", e)
    }
  }

  // If offline, return cached data or throw
  if (!isOnline) {
    if (cachedData) {
      console.log("[offlineFetch] Offline - returning cached data for:", cacheKey)
      return { data: cachedData.data, fromCache: true, isStale: cachedData.isStale }
    }
    throw new Error("Offline and no cached data available")
  }

  // If we have fresh cached data, return it
  if (cachedData && !cachedData.isStale && !skipCache) {
    console.log("[offlineFetch] Returning fresh cached data for:", cacheKey)
    return { data: cachedData.data, fromCache: true, isStale: false }
  }

  // If staleWhileRevalidate and we have stale data, return it and revalidate in background
  if (staleWhileRevalidate && cachedData?.isStale) {
    // Fire off background revalidation
    fetchAndCache(url, cacheKey, cacheTtl, fetchOptions).catch(console.error)
    
    return { data: cachedData.data, fromCache: true, isStale: true }
  }

  // Fetch fresh data
  try {
    const data = await fetchAndCache<T>(url, cacheKey, cacheTtl, fetchOptions)
    return { data, fromCache: false, isStale: false }
  } catch (error) {
    // On fetch error, try to return stale cached data
    if (cachedData) {
      console.warn("[offlineFetch] Fetch failed, returning stale cache for:", cacheKey)
      return { data: cachedData.data, fromCache: true, isStale: true }
    }
    throw error
  }
}

async function fetchAndCache<T>(
  url: string,
  cacheKey: string,
  cacheTtl: number,
  fetchOptions: RequestInit
): Promise<T> {
  const response = await fetch(url, fetchOptions)
  
  if (!response.ok) {
    throw new Error(`Fetch failed: ${response.status}`)
  }

  const data = await response.json()

  // Cache the response
  if (offlineStorage) {
    try {
      await offlineStorage.cacheApiResponse(cacheKey, data, cacheTtl)
    } catch (e) {
      console.warn("[offlineFetch] Cache write failed:", e)
    }
  }

  return data
}

/**
 * Pre-cache important API data for offline use
 */
export async function preCacheForOffline(userId?: string): Promise<void> {
  if (!offlineStorage || !navigator.onLine) return

  console.log("[offlineFetch] Pre-caching data for offline use...")

  const endpoints = [
    { url: "/api/genres", ttl: 24 * 60 * 60 * 1000 }, // 24 hours
    { url: "/api/categories", ttl: 24 * 60 * 60 * 1000 },
    { url: "/api/tracks/featured", ttl: 60 * 60 * 1000 }, // 1 hour
    { url: "/api/tracks/trending", ttl: 60 * 60 * 1000 },
  ]

  if (userId) {
    endpoints.push(
      { url: `/api/users/${userId}/playlists`, ttl: 30 * 60 * 1000 }, // 30 min
      { url: `/api/users/${userId}/liked-tracks`, ttl: 30 * 60 * 1000 },
    )
  }

  const results = await Promise.allSettled(
    endpoints.map(async ({ url, ttl }) => {
      try {
        await offlineFetch(url, { cacheTtl: ttl, skipCache: true })
        return url
      } catch (e) {
        console.warn(`[offlineFetch] Failed to pre-cache ${url}:`, e)
        throw e
      }
    })
  )

  const cached = results.filter(r => r.status === "fulfilled").length
  console.log(`[offlineFetch] Pre-cached ${cached}/${endpoints.length} endpoints`)
}

/**
 * Clear all offline cache
 */
export async function clearOfflineCache(): Promise<void> {
  if (!offlineStorage) return
  
  try {
    await offlineStorage.clearExpiredCache()
    console.log("[offlineFetch] Cleared expired cache")
  } catch (e) {
    console.error("[offlineFetch] Failed to clear cache:", e)
  }
}
