"use client"

import { createContext, useContext, useEffect, useState, useCallback } from "react"
import {
  configuredBackendUrl,
  defaultDataSourceMode,
  isBackendUrlLocked,
  isMockDataSourceAvailable,
  LOCAL_DEFAULT_BACKEND_URL,
  resolveStoredBackendUrl,
} from "@/lib/backend-url"
import { resolveApiUrl } from "@/shared/api/http-client"

// ── types ─────────────────────────────────────────────────────────────────────

export type DataSourceMode = "mock" | "live"

/** Режим «Живые» в настройках: моковые данные не подставлять. */
export function isLiveDataSourceMode(mode: DataSourceMode): boolean {
  return mode === "live"
}

interface DataSourceContextValue {
  mode:          DataSourceMode
  setMode:       (m: DataSourceMode) => void
  backendUrl:    string
  setBackendUrl: (url: string) => void
  backendUrlLocked: boolean
  mockModeAvailable: boolean
  /** localStorage для mode/backendUrl применён на клиенте (после первого paint). */
  prefsHydrated: boolean
  /** undefined = не проверялось, true = OK, false = недоступен */
  backendStatus: boolean | undefined
  checkBackend:  () => Promise<void>
}

// ── context ───────────────────────────────────────────────────────────────────

const DataSourceContext = createContext<DataSourceContextValue | null>(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 initialBackendUrl(): string {
  if (typeof window === "undefined") {
    const cfg = configuredBackendUrl()
    if (cfg.kind === "same-origin") return ""
    if (cfg.kind === "fixed") return cfg.url
    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<DataSourceMode>(defaultDataSourceMode)
  const [backendUrl, setBackendUrlState] = useState(initialBackendUrl)
  const [prefsHydrated, setPrefsHydrated] = useState(false)
  const [backendStatus, setBackendStatus] = useState<boolean | undefined>(undefined)
  const backendUrlLocked = isBackendUrlLocked()
  const mockModeAvailable = isMockDataSourceAvailable()

  useEffect(() => {
    const storedMode = readStoredMode()
    const url = resolveStoredBackendUrl(localStorage.getItem(LS_BACKEND))
    setModeState(storedMode)
    setBackendUrlState(url)
    setPrefsHydrated(true)
  }, [])

  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 healthUrl = resolveApiUrl(backendUrl, "/health")
    try {
      const res = await fetch(healthUrl, { signal: AbortSignal.timeout(3000) })
      setBackendStatus(res.ok)
    } catch {
      setBackendStatus(false)
    }
  }, [backendUrl])

  useEffect(() => {
    if (!prefsHydrated || mode !== "live") return
    queueMicrotask(() => { void checkBackend() })
  }, [prefsHydrated, mode, checkBackend])

  return (
    <DataSourceContext.Provider
      value={{ mode, setMode, backendUrl, setBackendUrl, backendUrlLocked, mockModeAvailable, prefsHydrated, backendStatus, checkBackend }}
    >
      {children}
    </DataSourceContext.Provider>
  )
}

export function useDataSource(): DataSourceContextValue {
  const ctx = useContext(DataSourceContext)
  if (!ctx) throw new Error("useDataSource must be used inside <DataSourceProvider>")
  return ctx
}
