import { createContext, useContext, useState, useEffect, useCallback, type ReactNode } from 'react'
import type { AppConfig } from '../types'
import { defaultConfig } from '../types'
import { loadConfig, saveConfig } from '../utils/storage'
import { S2AClient } from '../api/s2a'

interface ConfigContextValue {
  config: AppConfig
  updateConfig: (updates: Partial<AppConfig>) => void
  updateS2AConfig: (updates: Partial<AppConfig['s2a']>) => void
  updatePoolingConfig: (updates: Partial<AppConfig['pooling']>) => void
  updateCheckConfig: (updates: Partial<AppConfig['check']>) => void
  updateEmailConfig: (updates: Partial<AppConfig['email']>) => void
  isConnected: boolean
  testConnection: () => Promise<boolean>
  s2aClient: S2AClient | null
}

const ConfigContext = createContext<ConfigContextValue | null>(null)

export function ConfigProvider({ children }: { children: ReactNode }) {
  const [config, setConfig] = useState<AppConfig>(defaultConfig)
  const [isConnected, setIsConnected] = useState(false)
  const [s2aClient, setS2aClient] = useState<S2AClient | null>(null)

  // Load config from localStorage on mount
  useEffect(() => {
    const savedConfig = loadConfig()
    setConfig(savedConfig)

    // Create S2A client if config is available
    if (savedConfig.s2a.apiBase && savedConfig.s2a.adminKey) {
      const client = new S2AClient({
        baseUrl: savedConfig.s2a.apiBase,
        apiKey: savedConfig.s2a.adminKey,
      })
      setS2aClient(client)

      // Test connection on load
      client.testConnection().then(setIsConnected)
    }
  }, [])

  // Update S2A client when config changes
  useEffect(() => {
    if (config.s2a.apiBase && config.s2a.adminKey) {
      const client = new S2AClient({
        baseUrl: config.s2a.apiBase,
        apiKey: config.s2a.adminKey,
      })
      setS2aClient(client)
    } else {
      setS2aClient(null)
      setIsConnected(false)
    }
  }, [config.s2a.apiBase, config.s2a.adminKey])

  const updateConfig = useCallback((updates: Partial<AppConfig>) => {
    setConfig((prev) => {
      const newConfig = { ...prev, ...updates }
      saveConfig(newConfig)
      return newConfig
    })
  }, [])

  const updateS2AConfig = useCallback((updates: Partial<AppConfig['s2a']>) => {
    setConfig((prev) => {
      const newConfig = {
        ...prev,
        s2a: { ...prev.s2a, ...updates },
      }
      saveConfig(newConfig)
      return newConfig
    })
  }, [])

  const updatePoolingConfig = useCallback((updates: Partial<AppConfig['pooling']>) => {
    setConfig((prev) => {
      const newConfig = {
        ...prev,
        pooling: { ...prev.pooling, ...updates },
      }
      saveConfig(newConfig)
      return newConfig
    })
  }, [])

  const updateCheckConfig = useCallback((updates: Partial<AppConfig['check']>) => {
    setConfig((prev) => {
      const newConfig = {
        ...prev,
        check: { ...prev.check, ...updates },
      }
      saveConfig(newConfig)
      return newConfig
    })
  }, [])

  const updateEmailConfig = useCallback((updates: Partial<AppConfig['email']>) => {
    setConfig((prev) => {
      const newConfig = {
        ...prev,
        email: { ...prev.email, ...updates },
      }
      saveConfig(newConfig)
      return newConfig
    })
  }, [])

  const testConnection = useCallback(async (): Promise<boolean> => {
    try {
      // 使用后端代理 API 来测试 S2A 连接（避免 CORS 问题）
      const res = await fetch('http://localhost:8088/api/s2a/test')
      const connected = res.ok
      setIsConnected(connected)
      return connected
    } catch {
      setIsConnected(false)
      return false
    }
  }, [])

  return (
    <ConfigContext.Provider
      value={{
        config,
        updateConfig,
        updateS2AConfig,
        updatePoolingConfig,
        updateCheckConfig,
        updateEmailConfig,
        isConnected,
        testConnection,
        s2aClient,
      }}
    >
      {children}
    </ConfigContext.Provider>
  )
}

export function useConfigContext(): ConfigContextValue {
  const context = useContext(ConfigContext)
  if (!context) {
    throw new Error('useConfigContext must be used within a ConfigProvider')
  }
  return context
}
