import { getDb } from '../db/client.js'
import { publish } from '../plugins/valkey.js'
import { isUserOnlineWs, sendToSessionParticipant } from '../plugins/websocket.js'
import { sendPushNotification } from './notification.service.js'
import { UserType, SessionStatus, MessageStatus, MessageType, WsMessage } from '../constants.js'

const sql = getDb()

export const sendMessage = async ({ sessionId, senderType, senderId, content, type = MessageType.TEXT }) => {
  // Verify session is active
  const [session] = await sql`
    SELECT id, customer_id, mitra_id, status FROM chat_sessions
    WHERE id = ${sessionId} AND status = ${SessionStatus.ACTIVE}
  `
  if (!session) {
    throw Object.assign(new Error('Session is not active'), {
      code: 'SESSION_NOT_ACTIVE', statusCode: 409,
    })
  }

  // Save message
  const [message] = await sql`
    INSERT INTO chat_messages (session_id, sender_type, sender_id, type, content, status)
    VALUES (${sessionId}, ${senderType}, ${senderId}, ${type}, ${content}, ${MessageStatus.SENT})
    RETURNING id, session_id, sender_type, sender_id, type, content, status, created_at
  `

  // Send ack to sender
  sendToSessionParticipant(sessionId, senderType, {
    type: WsMessage.MESSAGE_ACK,
    message_id: message.id,
    status: MessageStatus.SENT,
    created_at: message.created_at,
  })

  // Determine recipient
  const recipientType = senderType === UserType.CUSTOMER ? UserType.MITRA : UserType.CUSTOMER
  const recipientId = senderType === UserType.CUSTOMER ? session.mitra_id : session.customer_id

  // Try to send via WebSocket
  const delivered = sendToSessionParticipant(sessionId, recipientType, {
    type: WsMessage.MESSAGE,
    message_id: message.id,
    sender_type: senderType,
    content: message.content,
    message_type: message.type,
    created_at: message.created_at,
  })

  // If recipient not connected via WebSocket, send FCM push
  if (!delivered && recipientId) {
    await sendPushNotification(recipientType, recipientId, {
      title: senderType === UserType.CUSTOMER ? 'Pesan baru dari Customer' : 'Pesan baru dari Bestie',
      body: content.length > 100 ? content.substring(0, 100) + '...' : content,
      data: { session_id: sessionId, type: 'chat_message' },
    })
  }

  return message
}

export const markDelivered = async (sessionId, senderType, messageIds) => {
  if (!messageIds || messageIds.length === 0) return

  await sql`
    UPDATE chat_messages
    SET status = ${MessageStatus.DELIVERED}, delivered_at = NOW()
    WHERE id = ANY(${messageIds})
      AND session_id = ${sessionId}
      AND status = ${MessageStatus.SENT}
  `

  // Notify sender about delivery
  const recipientType = senderType === UserType.CUSTOMER ? UserType.MITRA : UserType.CUSTOMER
  sendToSessionParticipant(sessionId, recipientType, {
    type: WsMessage.MESSAGE_STATUS,
    message_ids: messageIds,
    status: MessageStatus.DELIVERED,
  })
}

export const markRead = async (sessionId, senderType, messageIds) => {
  if (!messageIds || messageIds.length === 0) return

  await sql`
    UPDATE chat_messages
    SET status = ${MessageStatus.READ}, read_at = NOW()
    WHERE id = ANY(${messageIds})
      AND session_id = ${sessionId}
      AND status IN (${MessageStatus.SENT}, ${MessageStatus.DELIVERED})
  `

  // Notify sender about read
  const recipientType = senderType === UserType.CUSTOMER ? UserType.MITRA : UserType.CUSTOMER
  sendToSessionParticipant(sessionId, recipientType, {
    type: WsMessage.MESSAGE_STATUS,
    message_ids: messageIds,
    status: MessageStatus.READ,
  })
}

export const getMessages = async (sessionId, { limit = 50, before } = {}) => {
  const conditions = before
    ? sql`AND created_at < ${before}`
    : sql``

  const messages = await sql`
    SELECT id, session_id, sender_type, sender_id, type, content, status, delivered_at, read_at, created_at
    FROM chat_messages
    WHERE session_id = ${sessionId}
    ${conditions}
    ORDER BY created_at DESC
    LIMIT ${limit}
  `
  return messages.reverse() // Return in chronological order
}

export const getUndeliveredMessages = async (sessionId, recipientType) => {
  const senderType = recipientType === UserType.CUSTOMER ? UserType.MITRA : UserType.CUSTOMER
  return sql`
    SELECT id, session_id, sender_type, sender_id, type, content, status, created_at
    FROM chat_messages
    WHERE session_id = ${sessionId}
      AND sender_type = ${senderType}
      AND status = ${MessageStatus.SENT}
    ORDER BY created_at ASC
  `
}
