import React, { createContext, useContext, useState, useEffect, useCallback } from 'react'

const AuthContext = createContext(null)

const TOKEN_KEY = 'access_token'
const REFRESH_TOKEN_KEY = 'refresh_token'
const USER_KEY = 'user'

export function AuthProvider({ children }) {
  const [user, setUser] = useState(null)
  const [loading, setLoading] = useState(true)
  const [error, setError] = useState(null)

  const logout = useCallback(async () => {
    const token = localStorage.getItem(TOKEN_KEY)
    
    if (token) {
      try {
        await fetch('/api/auth/logout', {
          method: 'POST',
          headers: {
            'Authorization': `Bearer ${token}`,
            'Content-Type': 'application/json'
          }
        })
      } catch (err) {
        console.error('Logout error:', err)
      }
    }
    
    localStorage.removeItem(TOKEN_KEY)
    localStorage.removeItem(REFRESH_TOKEN_KEY)
    localStorage.removeItem(USER_KEY)
    setUser(null)
  }, [])

  const refreshToken = useCallback(async () => {
    const refresh = localStorage.getItem(REFRESH_TOKEN_KEY)
    
    if (!refresh) {
      return false
    }
    
    try {
      const response = await fetch('/api/auth/refresh', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ refresh_token: refresh })
      })
      
      if (!response.ok) {
        return false
      }
      
      const data = await response.json()
      
      localStorage.setItem(TOKEN_KEY, data.access_token)
      localStorage.setItem(REFRESH_TOKEN_KEY, data.refresh_token)
      localStorage.setItem(USER_KEY, JSON.stringify(data.user))
      setUser(data.user)
      
      return true
    } catch (err) {
      console.error('Refresh token error:', err)
      return false
    }
  }, [])

  // Initialize from localStorage
  useEffect(() => {
    const initAuth = async () => {
      const token = localStorage.getItem(TOKEN_KEY)
      const savedUser = localStorage.getItem(USER_KEY)
      
      if (token && savedUser) {
        try {
          setUser(JSON.parse(savedUser))
          // Verify token is still valid with timeout
          const controller = new AbortController()
          const timeoutId = setTimeout(() => controller.abort(), 5000) // 5 second timeout
          
          const response = await fetch('/api/auth/me', {
            headers: {
              'Authorization': `Bearer ${token}`,
              'Content-Type': 'application/json'
            },
            signal: controller.signal
          })
          
          clearTimeout(timeoutId)
          
          if (response.ok) {
            const data = await response.json()
            setUser(data.user)
            localStorage.setItem(USER_KEY, JSON.stringify(data.user))
          } else if (response.status === 401) {
            // Try to refresh token
            const refreshed = await refreshToken()
            if (!refreshed) {
              logout()
            }
          } else {
            // For other errors (like 503, 502, network errors), don't clear auth
            // Just log the error and keep the user logged in
            console.warn('Auth check failed with status:', response.status, 'but keeping session')
          }
        } catch (err) {
          // Network errors (e.g., backend not ready) should not clear auth
          // Only clear if it's a real auth error
          if (err.name === 'AbortError') {
            // Timeout - backend might be starting up, keep auth state
            console.warn('Auth check timeout, backend might be starting up. Keeping session.')
          } else if (err.name === 'TypeError' && (err.message.includes('fetch') || err.message.includes('Failed to fetch'))) {
            // Network error - backend might be starting up, keep auth state
            console.warn('Network error during auth check, keeping session:', err.message)
          } else {
            // Other errors - might be auth related
            console.error('Auth init error:', err)
            // Don't automatically logout on unknown errors
          }
        }
      }
      setLoading(false)
    }
    
    initAuth()
  }, [refreshToken, logout])

  const login = useCallback(async (email, password) => {
    setError(null)
    try {
      const response = await fetch('/api/auth/login', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ email, password })
      })
      
      const data = await response.json()
      
      if (!response.ok) {
        throw new Error(data.error || 'Ошибка входа')
      }
      
      localStorage.setItem(TOKEN_KEY, data.access_token)
      localStorage.setItem(REFRESH_TOKEN_KEY, data.refresh_token)
      localStorage.setItem(USER_KEY, JSON.stringify(data.user))
      setUser(data.user)
      
      return true
    } catch (err) {
      setError(err.message)
      return false
    }
  }, [])

  const register = useCallback(async (email, password, name) => {
    setError(null)
    try {
      const response = await fetch('/api/auth/register', {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json'
        },
        body: JSON.stringify({ email, password, name: name || undefined })
      })
      
      const data = await response.json()
      
      if (!response.ok) {
        throw new Error(data.error || 'Ошибка регистрации')
      }
      
      localStorage.setItem(TOKEN_KEY, data.access_token)
      localStorage.setItem(REFRESH_TOKEN_KEY, data.refresh_token)
      localStorage.setItem(USER_KEY, JSON.stringify(data.user))
      setUser(data.user)
      
      return true
    } catch (err) {
      setError(err.message)
      return false
    }
  }, [])

  const getToken = useCallback(() => {
    return localStorage.getItem(TOKEN_KEY)
  }, [])

  // Fetch wrapper that handles auth
  const authFetch = useCallback(async (url, options = {}) => {
    const token = localStorage.getItem(TOKEN_KEY)
    
    const headers = {
      'Content-Type': 'application/json',
      ...options.headers
    }
    
    if (token) {
      headers['Authorization'] = `Bearer ${token}`
    }
    
    try {
      let response = await fetch(url, { ...options, headers })
      
      // If 401, try to refresh token and retry
      if (response.status === 401) {
        const refreshed = await refreshToken()
        if (refreshed) {
          const newToken = localStorage.getItem(TOKEN_KEY)
          headers['Authorization'] = `Bearer ${newToken}`
          response = await fetch(url, { ...options, headers })
        } else {
          // Only logout if refresh failed (real auth error)
          logout()
        }
      }
      
      return response
    } catch (err) {
      // Network errors should not trigger logout
      // Let the caller handle the error
      throw err
    }
  }, [refreshToken, logout])

  const value = {
    user,
    loading,
    error,
    login,
    register,
    logout,
    getToken,
    authFetch,
    isAuthenticated: !!user
  }

  return (
    <AuthContext.Provider value={value}>
      {children}
    </AuthContext.Provider>
  )
}

export function useAuth() {
  const context = useContext(AuthContext)
  if (!context) {
    throw new Error('useAuth must be used within an AuthProvider')
  }
  return context
}

export default AuthContext

