import { closeRouter, getProducer, getTransport } from './mediasoup.js'
import { acquire } from './asyncLock.js'
import { LIVE_SESSION_TTL_MS } from './constants.js'

const sessions = new Map()

export const createSession = async (userId, label = '') => {
  return acquire(`session-create-${userId}`, async () => {
    const id = crypto.randomUUID()
    const session = {
      id,
      userId,
      label: (label || 'Live').trim() || 'Live',
      lat: 0,
      lng: 0,
      updatedAt: Date.now(),
      routerId: null,
      producerId: null,
      transportId: null,
    }
    sessions.set(id, session)
    return session
  })
}

/**
 * Atomically get existing active session or create new one for user.
 * @param {string} userId - User ID
 * @param {string} label - Session label
 * @returns {Promise<object>} Session object
 */
export const getOrCreateSession = async (userId, label = '') => {
  return acquire(`session-get-or-create-${userId}`, async () => {
    const now = Date.now()
    for (const s of sessions.values()) {
      if (s.userId === userId && now - s.updatedAt <= LIVE_SESSION_TTL_MS) {
        return s
      }
    }
    return await createSession(userId, label)
  })
}

export const getLiveSession = id => sessions.get(id)

export const getActiveSessionByUserId = async (userId) => {
  return acquire(`session-get-${userId}`, async () => {
    const now = Date.now()
    for (const s of sessions.values()) {
      if (s.userId === userId && now - s.updatedAt <= LIVE_SESSION_TTL_MS) return s
    }
  })
}

export const updateLiveSession = async (id, updates) => {
  return acquire(`session-update-${id}`, async () => {
    const session = sessions.get(id)
    if (!session) {
      throw new Error('Session not found')
    }
    const now = Date.now()
    if (Number.isFinite(updates.lat)) session.lat = updates.lat
    if (Number.isFinite(updates.lng)) session.lng = updates.lng
    if (updates.routerId !== undefined) session.routerId = updates.routerId
    if (updates.producerId !== undefined) session.producerId = updates.producerId
    if (updates.transportId !== undefined) session.transportId = updates.transportId
    session.updatedAt = now
    return session
  })
}

export const deleteLiveSession = async (id) => {
  await acquire(`session-delete-${id}`, async () => {
    sessions.delete(id)
  })
}

export const clearSessions = () => sessions.clear()

const cleanupSession = async (session) => {
  if (session.producerId) {
    const producer = getProducer(session.producerId)
    producer?.close()
  }
  if (session.transportId) {
    const transport = getTransport(session.transportId)
    transport?.close()
  }
  if (session.routerId) {
    await closeRouter(session.id).catch((err) => {
      console.error(`[liveSessions] Error closing router for expired session ${session.id}:`, err)
    })
  }
}

export const getActiveSessions = async () => {
  return acquire('get-active-sessions', async () => {
    const now = Date.now()
    const active = []
    const expired = []

    for (const session of sessions.values()) {
      if (now - session.updatedAt <= LIVE_SESSION_TTL_MS) {
        active.push({
          id: session.id,
          userId: session.userId,
          label: session.label,
          lat: session.lat,
          lng: session.lng,
          updatedAt: session.updatedAt,
          hasStream: Boolean(session.producerId),
        })
      }
      else {
        expired.push(session)
      }
    }

    for (const session of expired) {
      await cleanupSession(session)
      sessions.delete(session.id)
    }

    return active
  })
}
