"use client" import { createContext, useContext, useEffect, useState, useCallback } from "react" // ── types ───────────────────────────────────────────────────────────────────── export type DataSourceMode = "mock" | "live" interface DataSourceContextValue { mode: DataSourceMode setMode: (m: DataSourceMode) => void backendUrl: string setBackendUrl: (url: string) => void /** 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" const DEFAULT_URL = "http://localhost:8000" function readStoredMode(): DataSourceMode { if (typeof window === "undefined") return "mock" const stored = localStorage.getItem(LS_MODE) as DataSourceMode | null return stored === "mock" || stored === "live" ? stored : "mock" } function readStoredBackendUrl(): string { if (typeof window === "undefined") return DEFAULT_URL return localStorage.getItem(LS_BACKEND) ?? DEFAULT_URL } export function DataSourceProvider({ children }: { children: React.ReactNode }) { const [mode, setModeState] = useState("mock") const [backendUrl, setBackendUrlState] = useState(DEFAULT_URL) const [backendStatus, setBackendStatus] = useState(undefined) useEffect(() => { queueMicrotask(() => { const nextMode = readStoredMode() const nextBackendUrl = readStoredBackendUrl() setModeState(nextMode) setBackendUrlState(nextBackendUrl) }) }, []) const setMode = useCallback((m: DataSourceMode) => { setModeState(m) localStorage.setItem(LS_MODE, m) }, []) const setBackendUrl = useCallback((url: string) => { setBackendUrlState(url) localStorage.setItem(LS_BACKEND, url) }, []) const checkBackend = useCallback(async () => { const url = (localStorage.getItem(LS_BACKEND) ?? DEFAULT_URL).replace(/\/$/, "") try { const res = await fetch(`${url}/health`, { signal: AbortSignal.timeout(3000) }) setBackendStatus(res.ok) } catch { setBackendStatus(false) } }, []) // Auto-check when mode switches to live (defer to avoid set-state-in-effect rule on async loader) 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 }