import {
  createContext,
  useCallback,
  useContext,
  useEffect,
  useMemo,
  useState,
} from 'react'
import type { ReactNode } from 'react'
import { apiFetch } from '../api'
import type { CreationsStore } from '../lib/creations'
import {
  ensureWorkshopSamplesInStore,
  loadCreations,
  mergeCreationsStores,
  replaceCreationsStore,
  syncCreationsToServerIfAuthed,
} from '../lib/creations'

export type User = {
  id: string
  email: string
  firstName: string
  lastName: string
}

type AuthCtx = {
  user: User | null
  token: string | null
  loading: boolean
  setAuth: (user: User, token: string) => void
  signOut: () => void
  refreshUser: () => Promise<void>
}

const Ctx = createContext<AuthCtx | null>(null)

export function AuthProvider({ children }: { children: ReactNode }) {
  const [user, setUser] = useState<User | null>(null)
  const [token, setToken] = useState<string | null>(() => localStorage.getItem('authToken'))
  const [loading, setLoading] = useState(true)

  /** Merge server-saved workshop records with localStorage, then upload merged snapshot. */
  const hydrateWorkshopCreations = useCallback(async () => {
    const pr = await apiFetch('/api/users/me/profile')
    if (!pr.ok) return
    const profile = (await pr.json()) as { creations?: CreationsStore }
    const raw = profile.creations
    const remoteStore: CreationsStore = {
      personas: Array.isArray(raw?.personas) ? raw!.personas : [],
      advisorPanels: Array.isArray(raw?.advisorPanels) ? raw!.advisorPanels : [],
    }
    const localBefore = loadCreations()
    const merged = mergeCreationsStores(localBefore, remoteStore)
    const withSamples = ensureWorkshopSamplesInStore(merged)
    replaceCreationsStore(withSamples, { skipServerSync: true })
    void syncCreationsToServerIfAuthed()
  }, [])

  const refreshUser = useCallback(async () => {
    const t = localStorage.getItem('authToken')
    if (!t) {
      setUser(null)
      setToken(null)
      return
    }
    const r = await apiFetch('/api/auth/me')
    if (r.ok) {
      const u = (await r.json()) as User
      setUser(u)
      setToken(t)
      localStorage.setItem('user', JSON.stringify(u))
      await hydrateWorkshopCreations()
    } else {
      localStorage.removeItem('authToken')
      localStorage.removeItem('user')
      setUser(null)
      setToken(null)
    }
  }, [hydrateWorkshopCreations])

  useEffect(() => {
    let cancelled = false
    ;(async () => {
      const t = localStorage.getItem('authToken')
      if (!t) {
        if (!cancelled) setLoading(false)
        return
      }
      const r = await apiFetch('/api/auth/me')
      if (cancelled) return
      if (r.ok) {
        const u = (await r.json()) as User
        setUser(u)
        setToken(t)
        localStorage.setItem('user', JSON.stringify(u))
        await hydrateWorkshopCreations()
      } else {
        localStorage.removeItem('authToken')
        localStorage.removeItem('user')
        setUser(null)
        setToken(null)
      }
      setLoading(false)
    })()
    return () => {
      cancelled = true
    }
  }, [hydrateWorkshopCreations])

  const setAuth = useCallback(
    (u: User, tok: string) => {
      localStorage.setItem('authToken', tok)
      localStorage.setItem('user', JSON.stringify(u))
      setUser(u)
      setToken(tok)
      void hydrateWorkshopCreations()
    },
    [hydrateWorkshopCreations],
  )

  const signOut = useCallback(() => {
    localStorage.removeItem('authToken')
    localStorage.removeItem('user')
    setUser(null)
    setToken(null)
  }, [])

  const value = useMemo(
    () => ({ user, token, loading, setAuth, signOut, refreshUser }),
    [user, token, loading, setAuth, signOut, refreshUser],
  )

  return <Ctx.Provider value={value}>{children}</Ctx.Provider>
}

export function useAuth() {
  const v = useContext(Ctx)
  if (!v) throw new Error('useAuth outside AuthProvider')
  return v
}
