import { useEffect, useState } from 'react'
import Taro from '@tarojs/taro'
import { isLoggedOut, login } from '@/services/auth.service'
import { mockProfile } from '@/services/mock'
import { requestTab } from '@/store/homeTab'
import type { UserProfile } from '@/types/domain'

// Single shared session for the whole app. Previously every page that needed the
// user ran its own `login()` cloud call on mount, so each navigation paid a
// roundtrip before it could render — the main cause of the post-login lag. Now we
// log in once, cache the result in memory (+ Storage for instant cold starts),
// and hand the same user to every page.

const SESSION_KEY = 'wq:session'

let cachedUser: UserProfile | null = null
let inflight: Promise<UserProfile> | null = null
const subscribers = new Set<(user: UserProfile) => void>()

function readStoredUser(): UserProfile | null {
  try {
    const stored = Taro.getStorageSync(SESSION_KEY)
    return stored && typeof stored === 'object' ? (stored as UserProfile) : null
  } catch {
    return null
  }
}

function persist(user: UserProfile) {
  try {
    Taro.setStorageSync(SESSION_KEY, user)
  } catch {
    /* storage unavailable — in-memory cache still works for this run */
  }
}

/** Best-effort synchronous user for first paint (memory → Storage → mock). */
export function getCachedUser(): UserProfile {
  if (cachedUser) return cachedUser
  const stored = readStoredUser()
  if (stored) {
    cachedUser = stored
    return stored
  }
  return mockProfile
}

function broadcast(user: UserProfile) {
  cachedUser = user
  persist(user)
  subscribers.forEach(fn => fn(user))
}

/**
 * Resolve the logged-in user, hitting the `login` cloud function at most once.
 * Concurrent callers share the same in-flight promise; later callers reuse the
 * cached result. Pass `force` to re-run login (e.g. after a fresh authorization).
 */
export function ensureLogin(force = false): Promise<UserProfile> {
  if (!force && cachedUser) return Promise.resolve(cachedUser)
  if (!force && inflight) return inflight

  inflight = login()
    .then(({ user }) => {
      broadcast(user)
      return user
    })
    .catch(() => getCachedUser())
    .finally(() => {
      inflight = null
    })

  return inflight
}

/** Update the shared user (after editing profile, completing login, etc.). */
export function setSessionUser(user: UserProfile) {
  broadcast(user)
}

/** Drop the cached session (on logout). */
export function clearSession() {
  cachedUser = null
  try {
    Taro.removeStorageSync(SESSION_KEY)
  } catch {
    /* ignore */
  }
  subscribers.forEach(fn => fn(mockProfile))
}

export async function ensureProfileReady(message = '请先完成登录资料'): Promise<boolean> {
  const user = await ensureLogin()
  if (!isLoggedOut() && user.profileCompleted) return true

  requestTab('profile')
  Taro.showToast({ title: message, icon: 'none' })
  return false
}

export function useSession() {
  const [user, setUser] = useState<UserProfile>(getCachedUser)

  useEffect(() => {
    subscribers.add(setUser)
    ensureLogin().then(setUser)
    return () => {
      subscribers.delete(setUser)
    }
  }, [])

  return { user, setUser: setSessionUser }
}
