/**
 * Firebase service - ported from services/firebaseChat.js
 * Now reads config from runtime config instead of hardcoded values.
 */
import { initializeApp, getApps, getApp } from 'firebase/app'
import type { FirebaseApp } from 'firebase/app'
import { getAuth, signInWithCustomToken, onAuthStateChanged } from 'firebase/auth'
import {
  getFirestore,
  collection,
  query,
  orderBy,
  onSnapshot,
  doc,
  setDoc,
  Timestamp,
} from 'firebase/firestore'
import { getMessaging, getToken, onMessage } from 'firebase/messaging'

let firebaseApp: FirebaseApp | null = null

export function getFirebaseApp() {
  if (firebaseApp) return firebaseApp

  const config = useRuntimeConfig()
  const fbConfig = config.public.firebase as Record<string, string>

  if (!fbConfig.apiKey) {
    console.warn('Firebase config not set. Add NUXT_PUBLIC_FIREBASE_* env vars.')
    return null
  }

  firebaseApp = getApps().length ? getApp() : initializeApp({
    apiKey: fbConfig.apiKey,
    authDomain: fbConfig.authDomain,
    projectId: fbConfig.projectId,
    storageBucket: fbConfig.storageBucket,
    messagingSenderId: fbConfig.messagingSenderId,
    appId: fbConfig.appId,
    measurementId: fbConfig.measurementId,
  })

  return firebaseApp
}

// --- Auth Ready Promise ---
let _authReadyResolve: (() => void) | null = null
let _authReady = new Promise<void>((resolve) => { _authReadyResolve = resolve })
let _isAuthReady = false

function initAuthListener() {
  const app = getFirebaseApp()
  if (!app) return

  const auth = getAuth(app)
  onAuthStateChanged(auth, (user) => {
    if (user && !_isAuthReady) {
      _isAuthReady = true
      _authReadyResolve?.()
    }
  })
}

export function waitForAuth() {
  if (_isAuthReady) return Promise.resolve()
  return _authReady
}

function resetAuthReady() {
  _isAuthReady = false
  _authReady = new Promise<void>((resolve) => { _authReadyResolve = resolve })
}

// --- Deterministic Chat ID ---
export function getChatId(userId: number, adminId: number): string {
  const a = Math.min(userId, adminId)
  const b = Math.max(userId, adminId)
  return `support_${a}_${b}`
}

// --- Firebase Authentication ---
let tokenRefreshTimer: ReturnType<typeof setInterval> | null = null

export async function initFirebaseAuth(token: string) {
  const app = getFirebaseApp()
  if (!app) return

  try {
    const config = useRuntimeConfig()
    const res = await $fetch<{ data: { custom_token: string } }>('/firebase/token', {
      baseURL: config.public.apiBaseUrl as string,
      method: 'POST',
      headers: { Authorization: `Bearer ${token}` },
    })
    const auth = getAuth(app)
    await signInWithCustomToken(auth, res.data.custom_token)
    initAuthListener()
  } catch (error) {
    console.error('Firebase auth failed:', error)
  }
}

export function scheduleTokenRefresh(token: string) {
  if (tokenRefreshTimer) clearInterval(tokenRefreshTimer)
  tokenRefreshTimer = setInterval(async () => {
    try {
      await initFirebaseAuth(token)
    } catch (e) {
      console.error('Firebase token refresh failed:', e)
    }
  }, 55 * 60 * 1000)
}

export function clearTokenRefresh() {
  if (tokenRefreshTimer) {
    clearInterval(tokenRefreshTimer)
    tokenRefreshTimer = null
  }
}

// --- FCM Push Notifications ---
export async function getFcmToken() {
  const app = getFirebaseApp()
  if (!app) return null

  const config = useRuntimeConfig()
  const fbConfig = config.public.firebase as Record<string, string>
  const messaging = getMessaging(app)
  return getToken(messaging, { vapidKey: fbConfig.vapidKey })
}

export function onForegroundMessage(callback: (payload: any) => void) {
  const app = getFirebaseApp()
  if (!app) return () => {}

  const messaging = getMessaging(app)
  return onMessage(messaging, callback)
}

// --- Messages Listener ---
let messageUnsubscribe: (() => void) | null = null

export async function listenToMessages(
  myId: number,
  otherId: number,
  onNewMessage: (msg: any) => void,
) {
  if (messageUnsubscribe) messageUnsubscribe()

  await waitForAuth()

  const app = getFirebaseApp()
  if (!app) return

  const firestore = getFirestore(app)
  const chatId = getChatId(myId, otherId)
  const messagesRef = collection(firestore, 'support_chats', chatId, 'messages')
  const q = query(messagesRef, orderBy('createdAt', 'asc'))

  messageUnsubscribe = onSnapshot(q, (snapshot) => {
    snapshot.docChanges().forEach((change) => {
      if (change.type === 'added') {
        const msg = change.doc.data()
        onNewMessage({
          message: msg.message,
          sender_id: parseInt(msg.senderId),
          receiver_id: parseInt(msg.receiverId),
          created_at: msg.createdAt?.toDate?.() || new Date(),
          is_file: msg.type === 'file' ? 1 : 0,
          seen_status: msg.seenStatus,
          message_id: msg.mysqlMessageId,
          firestore_id: change.doc.id,
        })
      }
    })
  })
}

export function stopListeningToMessages() {
  if (messageUnsubscribe) {
    messageUnsubscribe()
    messageUnsubscribe = null
  }
}

// --- Typing Indicators ---
let typingUnsubscribe: (() => void) | null = null

export async function setTyping(myId: number, otherId: number, isTyping: boolean) {
  try {
    await waitForAuth()
    const app = getFirebaseApp()
    if (!app) return

    const firestore = getFirestore(app)
    const chatId = getChatId(myId, otherId)
    const typingRef = doc(firestore, 'support_chats', chatId, 'typing', String(myId))
    await setDoc(typingRef, { isTyping, updatedAt: Timestamp.now() })
  } catch (error) {
    console.error('setTyping error:', error)
  }
}

export async function listenToTyping(
  myId: number,
  otherId: number,
  onTypingChange: (isTyping: boolean) => void,
) {
  if (typingUnsubscribe) typingUnsubscribe()

  await waitForAuth()

  const app = getFirebaseApp()
  if (!app) return

  const firestore = getFirestore(app)
  const chatId = getChatId(myId, otherId)
  const typingRef = doc(firestore, 'support_chats', chatId, 'typing', String(otherId))

  typingUnsubscribe = onSnapshot(typingRef, (snapshot) => {
    if (snapshot.exists()) {
      onTypingChange(snapshot.data().isTyping || false)
    } else {
      onTypingChange(false)
    }
  })
}

export function stopListeningToTyping() {
  if (typingUnsubscribe) {
    typingUnsubscribe()
    typingUnsubscribe = null
  }
}

// --- Online/Offline Presence ---
export async function setMyPresence(myId: number, isOnline: boolean) {
  try {
    await waitForAuth()
    const app = getFirebaseApp()
    if (!app) return

    const firestore = getFirestore(app)
    const presenceRef = doc(firestore, 'users_presence', String(myId))
    await setDoc(presenceRef, { isOnline, lastSeen: Timestamp.now() })
  } catch (error) {
    console.error('setMyPresence error:', error)
  }
}

let presenceUnsubscribe: (() => void) | null = null

export async function listenToPresence(
  userId: number,
  onStatusChange: (status: { isOnline: boolean; lastSeen: Date | null }) => void,
) {
  if (presenceUnsubscribe) presenceUnsubscribe()

  await waitForAuth()

  const app = getFirebaseApp()
  if (!app) return

  const firestore = getFirestore(app)
  const presenceRef = doc(firestore, 'users_presence', String(userId))

  presenceUnsubscribe = onSnapshot(presenceRef, (snapshot) => {
    if (snapshot.exists()) {
      const data = snapshot.data()
      onStatusChange({
        isOnline: data.isOnline || false,
        lastSeen: data.lastSeen?.toDate?.() || null,
      })
    } else {
      onStatusChange({ isOnline: false, lastSeen: null })
    }
  })
}

export function stopListeningToPresence() {
  if (presenceUnsubscribe) {
    presenceUnsubscribe()
    presenceUnsubscribe = null
  }
}

// --- Chat Meta (seen/unread counts) ---
let chatMetaUnsubscribe: (() => void) | null = null

export async function listenToChatMeta(
  myId: number,
  otherId: number,
  onUpdate: (data: { myUnread: number; otherUnread: number; lastMessage: string | null }) => void,
) {
  if (chatMetaUnsubscribe) chatMetaUnsubscribe()

  await waitForAuth()

  const app = getFirebaseApp()
  if (!app) return

  const firestore = getFirestore(app)
  const chatId = getChatId(myId, otherId)
  const chatRef = doc(firestore, 'support_chats', chatId)

  chatMetaUnsubscribe = onSnapshot(chatRef, (snapshot) => {
    if (snapshot.exists()) {
      const data = snapshot.data()
      const iAmUser = String(myId) === String(data.userId)
      onUpdate({
        myUnread: iAmUser ? (data.unreadByUser || 0) : (data.unreadByAdmin || 0),
        otherUnread: iAmUser ? (data.unreadByAdmin || 0) : (data.unreadByUser || 0),
        lastMessage: data.lastMessage || null,
      })
    }
  })
}

export function stopListeningToChatMeta() {
  if (chatMetaUnsubscribe) {
    chatMetaUnsubscribe()
    chatMetaUnsubscribe = null
  }
}

// --- Notification Count ---
let notificationUnsubscribe: (() => void) | null = null

export async function listenToNotificationCount(
  userId: number,
  onCountChange: (count: number) => void,
) {
  if (notificationUnsubscribe) notificationUnsubscribe()

  await waitForAuth()

  const app = getFirebaseApp()
  if (!app) return

  const firestore = getFirestore(app)
  const presenceRef = doc(firestore, 'users_presence', String(userId))

  notificationUnsubscribe = onSnapshot(presenceRef, (snapshot) => {
    if (snapshot.exists()) {
      onCountChange(snapshot.data().unreadNotifications || 0)
    } else {
      onCountChange(0)
    }
  })
}

export function stopListeningToNotificationCount() {
  if (notificationUnsubscribe) {
    notificationUnsubscribe()
    notificationUnsubscribe = null
  }
}

// --- Chat Unread Count ---
let chatUnreadUnsubscribe: (() => void) | null = null

export async function listenToChatUnreadCount(
  myId: number,
  otherId: number,
  onCountChange: (count: number) => void,
) {
  if (chatUnreadUnsubscribe) chatUnreadUnsubscribe()

  await waitForAuth()

  const app = getFirebaseApp()
  if (!app) return

  const firestore = getFirestore(app)
  const chatId = getChatId(myId, otherId)
  const chatRef = doc(firestore, 'support_chats', chatId)

  chatUnreadUnsubscribe = onSnapshot(chatRef, (snapshot) => {
    if (snapshot.exists()) {
      const data = snapshot.data()
      const iAmUser = String(myId) === String(data.userId)
      onCountChange(iAmUser ? (data.unreadByUser || 0) : (data.unreadByAdmin || 0))
    } else {
      onCountChange(0)
    }
  })
}

export function stopListeningToChatUnreadCount() {
  if (chatUnreadUnsubscribe) {
    chatUnreadUnsubscribe()
    chatUnreadUnsubscribe = null
  }
}

// --- Cleanup ---
export function cleanupFirebase() {
  stopListeningToMessages()
  stopListeningToTyping()
  stopListeningToPresence()
  stopListeningToChatMeta()
  stopListeningToNotificationCount()
  stopListeningToChatUnreadCount()
  clearTokenRefresh()
  resetAuthReady()
}
