"use client" import { createContext, useContext, useEffect, useState, useCallback } from "react" import { configuredBackendUrl, defaultDataSourceMode, isBackendUrlLocked, isMockDataSourceAvailable, LOCAL_DEFAULT_BACKEND_URL, resolveStoredBackendUrl, } from "@/lib/backend-url" // ── types ───────────────────────────────────────────────────────────────────── export type DataSourceMode = "mock" | "live" interface DataSourceContextValue { mode: DataSourceMode setMode: (m: DataSourceMode) => void backendUrl: string setBackendUrl: (url: string) => void backendUrlLocked: boolean mockModeAvailable: boolean /** undefined = не проверялось, true = OK, false = недоступен */ backendStatus: boolean | undefined checkBackend: () => Promise } // ── context ─────────────────────────────────────────────────────────────────── const DataSourceContext = createContext(null) const LS_MODE = "routerlists:data-source" const LS_BACKEND = "routerlists:backend-url" function readStoredMode(): DataSourceMode { if (!isMockDataSourceAvailable()) return "live" if (typeof window === "undefined") return defaultDataSourceMode() const stored = localStorage.getItem(LS_MODE) as DataSourceMode | null if (stored === "live") return "live" if (stored === "mock") return "mock" return defaultDataSourceMode() } function readStoredBackendUrl(): string { if (typeof window === "undefined") return LOCAL_DEFAULT_BACKEND_URL return resolveStoredBackendUrl(localStorage.getItem(LS_BACKEND)) } function normalizeBackendUrl(url: string): string { return url.trim().replace(/\/$/, "") } export function DataSourceProvider({ children }: { children: React.ReactNode }) { const [mode, setModeState] = useState(() => typeof window === "undefined" ? defaultDataSourceMode() : readStoredMode(), ) const [backendUrl, setBackendUrlState] = useState(() => typeof window === "undefined" ? LOCAL_DEFAULT_BACKEND_URL : readStoredBackendUrl(), ) const [backendStatus, setBackendStatus] = useState(undefined) const backendUrlLocked = isBackendUrlLocked() const mockModeAvailable = isMockDataSourceAvailable() useEffect(() => { if (configuredBackendUrl().kind !== "same-origin") return setBackendUrlState(window.location.origin) }, []) const setMode = useCallback((m: DataSourceMode) => { if (!mockModeAvailable && m === "mock") return setModeState(m) localStorage.setItem(LS_MODE, m) }, [mockModeAvailable]) const setBackendUrl = useCallback((url: string) => { if (backendUrlLocked) return const normalized = normalizeBackendUrl(url) setBackendUrlState(normalized) localStorage.setItem(LS_BACKEND, normalized) }, [backendUrlLocked]) const checkBackend = useCallback(async () => { const url = normalizeBackendUrl(backendUrl) try { const res = await fetch(`${url}/health`, { signal: AbortSignal.timeout(3000) }) setBackendStatus(res.ok) } catch { setBackendStatus(false) } }, [backendUrl]) useEffect(() => { if (mode === "live") queueMicrotask(() => { void checkBackend() }) }, [mode, checkBackend]) return ( {children} ) } export function useDataSource(): DataSourceContextValue { const ctx = useContext(DataSourceContext) if (!ctx) throw new Error("useDataSource must be used inside ") return ctx }