import { createContext, useContext, useEffect, useState } from 'react'
import type { User, AuthSession } from '../types'
import { api, ApiError } from '../lib/api'

const BASE = (import.meta.env.VITE_API_URL as string | undefined) ?? 'https://api.hotelsync.ru'

interface AuthContextValue {
  session: AuthSession | null
  user: User | null
  login: (email: string, password: string) => Promise<User | null>
  logout: () => void
}

const AuthContext = createContext<AuthContextValue | null>(null)

function loadSession(): AuthSession | null {
  try {
    const stored = localStorage.getItem('hotelsync-session')
    if (!stored) return null
    const parsed = JSON.parse(stored) as AuthSession
    // If session is missing token — discard it, we'll refresh below
    if (!parsed?.user) { localStorage.removeItem('hotelsync-session'); return null }
    return parsed
  } catch {
    localStorage.removeItem('hotelsync-session')
    return null
  }
}

export function AuthProvider({ children }: { children: React.ReactNode }) {
  const [session, setSession] = useState<AuthSession | null>(loadSession)

  // On mount: if session exists but token is missing/null, try to refresh via cookie
  useEffect(() => {
    if (!session) return
    if (session.token) return // token present, all good

    fetch(`${BASE}/api/auth/refresh`, { method: 'POST', credentials: 'include' })
      .then(r => r.ok ? r.json() : null)
      .then((data: { access_token?: string } | null) => {
        if (data?.access_token) {
          const tok = data.access_token
          setSession(cur => {
            if (!cur) return null
            const s: AuthSession = { ...cur, token: tok }
            localStorage.setItem('hotelsync-session', JSON.stringify(s))
            return s
          })
        } else {
          // Guard: if login() set a fresh token while refresh was in-flight — keep it
          setSession(cur => {
            if (cur?.token) return cur
            localStorage.removeItem('hotelsync-session')
            return null
          })
        }
      })
      .catch(() => {
        // Guard: same race-condition protection
        setSession(cur => {
          if (cur?.token) return cur
          localStorage.removeItem('hotelsync-session')
          return null
        })
      })
  }, []) // eslint-disable-line react-hooks/exhaustive-deps

  // Keep React state in sync when api.ts refreshes the token (e.g. after 401 auto-refresh)
  useEffect(() => {
    const handler = (e: Event) => {
      const { token } = (e as CustomEvent<{ token: string }>).detail
      setSession(cur => {
        if (!cur) return cur
        return { ...cur, token }
      })
    }
    window.addEventListener('hotelsync:token-updated', handler)
    return () => window.removeEventListener('hotelsync:token-updated', handler)
  }, [])

  const login = async (email: string, password: string): Promise<User | null> => {
    try {
      const { access_token, user } = await api.auth.login(email, password)
      const s: AuthSession = { user, token: access_token }
      setSession(s)
      localStorage.setItem('hotelsync-session', JSON.stringify(s))
      return user
    } catch (err) {
      if (err instanceof ApiError && err.status === 401) return null
      throw err
    }
  }

  const logout = async () => {
    try { await api.auth.logout() } catch { /* ignore */ }
    setSession(null)
    localStorage.removeItem('hotelsync-session')
  }

  return (
    <AuthContext.Provider value={{ session, user: session?.user ?? null, login, logout }}>
      {children}
    </AuthContext.Provider>
  )
}

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