import { getDb } from '../db/client.js'
import { SessionStatus } from '../constants.js'
import { getMitraPingConfig } from './config.service.js'

const sql = getDb()

export const ensureStatusRow = async (mitraId) => {
  await sql`
    INSERT INTO mitra_online_status (mitra_id)
    VALUES (${mitraId})
    ON CONFLICT (mitra_id) DO NOTHING
  `
}

export const setOnline = async (mitraId) => {
  await ensureStatusRow(mitraId)
  const now = new Date()
  await sql`
    UPDATE mitra_online_status
    SET is_online = true, last_online_at = ${now}, last_heartbeat_at = ${now}, updated_at = ${now}
    WHERE mitra_id = ${mitraId}
  `
  await sql`
    INSERT INTO mitra_online_logs (mitra_id, status) VALUES (${mitraId}, 'online')
  `
}

export const setOffline = async (mitraId) => {
  await ensureStatusRow(mitraId)
  const now = new Date()
  const [status] = await sql`
    SELECT is_online FROM mitra_online_status WHERE mitra_id = ${mitraId}
  `
  if (!status?.is_online) return

  await sql`
    UPDATE mitra_online_status
    SET is_online = false, last_offline_at = ${now}, updated_at = ${now}
    WHERE mitra_id = ${mitraId}
  `
  await sql`
    INSERT INTO mitra_online_logs (mitra_id, status) VALUES (${mitraId}, 'offline')
  `
}

export const heartbeat = async (mitraId) => {
  const now = new Date()
  await sql`
    UPDATE mitra_online_status
    SET last_heartbeat_at = ${now}, updated_at = ${now}
    WHERE mitra_id = ${mitraId} AND is_online = true
  `
}

export const getStatus = async (mitraId) => {
  await ensureStatusRow(mitraId)
  const [status] = await sql`
    SELECT is_online, last_online_at, last_offline_at, updated_at
    FROM mitra_online_status
    WHERE mitra_id = ${mitraId}
  `
  const pingConfig = await getMitraPingConfig()
  return {
    ...status,
    require_ping: pingConfig.require_ping,
    ping_interval_seconds: pingConfig.ping_interval_seconds,
  }
}

export const getOnlineMitras = async () => {
  const mitras = await sql`
    SELECT m.id, m.display_name, m.phone, s.last_online_at, s.updated_at,
      (SELECT COUNT(*) FROM chat_sessions cs
       WHERE cs.mitra_id = m.id AND cs.status IN (${SessionStatus.ACTIVE}, ${SessionStatus.PENDING_PAYMENT})) AS active_session_count
    FROM mitras m
    INNER JOIN mitra_online_status s ON s.mitra_id = m.id
    WHERE s.is_online = true AND m.is_active = true
    ORDER BY s.last_online_at DESC
  `
  return mitras
}

export const getOnlineLogs = async (mitraId, { page = 1, limit = 50 } = {}) => {
  const offset = (page - 1) * limit
  const items = await sql`
    SELECT id, status, timestamp
    FROM mitra_online_logs
    WHERE mitra_id = ${mitraId}
    ORDER BY timestamp DESC
    LIMIT ${limit} OFFSET ${offset}
  `
  const [{ count }] = await sql`
    SELECT COUNT(*) FROM mitra_online_logs WHERE mitra_id = ${mitraId}
  `
  return { items, total: Number(count), page, limit }
}

export const autoOfflineStaleMitras = async () => {
  const pingConfig = await getMitraPingConfig()

  // If ping is not required, skip the auto-offline sweep entirely
  if (!pingConfig.require_ping) return 0

  const staleSeconds = pingConfig.ping_interval_seconds * 3
  const stale = await sql`
    UPDATE mitra_online_status
    SET is_online = false, last_offline_at = NOW(), updated_at = NOW()
    WHERE is_online = true
      AND last_heartbeat_at < NOW() - ${staleSeconds + ' seconds'}::interval
    RETURNING mitra_id
  `

  for (const row of stale) {
    await sql`
      INSERT INTO mitra_online_logs (mitra_id, status) VALUES (${row.mitra_id}, 'offline')
    `
  }

  return stale.length
}
