import { getDb } from '../db/client.js'
import { publish } from '../plugins/valkey.js'
import { clearSessionTimer, clearClosureGraceTimer, startClosureGraceTimer } from './session-timer.service.js'
import { sendToSessionParticipant } from '../plugins/websocket.js'
import { sendPushNotification } from './notification.service.js'
import { UserType, SessionStatus, EndedBy, WsMessage } from '../constants.js'

const sql = getDb()

export const submitClosureMessage = async (sessionId, userType, userId, message) => {
  // Verify session is in closing or active state (for early end)
  const [session] = await sql`
    SELECT id, status FROM chat_sessions
    WHERE id = ${sessionId} AND status IN (${SessionStatus.CLOSING}, ${SessionStatus.ACTIVE}, ${SessionStatus.EXTENDING})
  `
  if (!session) {
    throw Object.assign(new Error('Session not found or already completed'), {
      code: 'SESSION_NOT_ACTIVE', statusCode: 409,
    })
  }

  // Save closure message
  const [closure] = await sql`
    INSERT INTO session_closures (session_id, user_type, user_id, message)
    VALUES (${sessionId}, ${userType}, ${userId}, ${message})
    ON CONFLICT DO NOTHING
    RETURNING id, session_id, user_type, message, created_at
  `

  // Customer submitted their goodbye — cancel the auto-close grace timer.
  // (Even if mitra hasn't submitted yet, the session is no longer "stuck".)
  if (userType === UserType.CUSTOMER) {
    clearClosureGraceTimer(sessionId)
  }

  // Check if both parties have submitted
  const closures = await sql`
    SELECT user_type FROM session_closures WHERE session_id = ${sessionId}
  `
  const hasCustomer = closures.some((c) => c.user_type === UserType.CUSTOMER)
  const hasMitra = closures.some((c) => c.user_type === UserType.MITRA)

  if (hasCustomer && hasMitra) {
    // Both submitted — complete the session
    await completeSession(sessionId)
  }

  return closure
}

export const completeSession = async (sessionId) => {
  clearSessionTimer(sessionId)
  clearClosureGraceTimer(sessionId)

  const [session] = await sql`
    UPDATE chat_sessions
    SET status = ${SessionStatus.COMPLETED}, ended_at = NOW(), ended_by = ${EndedBy.SYSTEM}
    WHERE id = ${sessionId} AND status IN (${SessionStatus.CLOSING}, ${SessionStatus.ACTIVE}, ${SessionStatus.EXTENDING})
    RETURNING id, customer_id, mitra_id, status, ended_at
  `
  if (!session) return null

  // Notify both parties, FCM fallback if WebSocket is down
  const data = { type: WsMessage.SESSION_COMPLETED, session_id: sessionId }
  const customerSent = sendToSessionParticipant(sessionId, UserType.CUSTOMER, data)
  const mitraSent = sendToSessionParticipant(sessionId, UserType.MITRA, data)

  if (!customerSent) {
    await sendPushNotification(UserType.CUSTOMER, session.customer_id, {
      title: 'Sesi Selesai',
      body: 'Sesi curhat kamu telah selesai.',
      data: { type: WsMessage.SESSION_COMPLETED, session_id: sessionId },
    })
  }
  if (!mitraSent) {
    await sendPushNotification(UserType.MITRA, session.mitra_id, {
      title: 'Sesi Selesai',
      body: 'Sesi curhat telah selesai.',
      data: { type: WsMessage.SESSION_COMPLETED, session_id: sessionId },
    })
  }

  await publish(`session:${sessionId}:status`, { type: WsMessage.SESSION_ENDED, session_id: sessionId })

  return session
}

export const initiateEarlyEnd = async (sessionId, userType) => {
  // Check if early end is enabled for this user type
  const configKey = userType === UserType.MITRA ? 'early_end_mitra_enabled' : 'early_end_customer_enabled'
  const [configRow] = await sql`SELECT value FROM app_config WHERE key = ${configKey}`
  const enabled = configRow?.value?.value ?? false

  if (!enabled) {
    throw Object.assign(new Error('Early end is not enabled'), {
      code: 'EARLY_END_DISABLED', statusCode: 403,
    })
  }

  // Move session to closing
  const [session] = await sql`
    UPDATE chat_sessions
    SET status = ${SessionStatus.CLOSING}, ended_by = ${userType}
    WHERE id = ${sessionId} AND status = ${SessionStatus.ACTIVE}
    RETURNING id, customer_id, mitra_id
  `
  if (!session) {
    throw Object.assign(new Error('Session not active'), {
      code: 'SESSION_NOT_ACTIVE', statusCode: 409,
    })
  }

  clearSessionTimer(sessionId)
  startClosureGraceTimer(sessionId)

  // Notify both parties to enter closure flow, FCM fallback if WebSocket is down
  const data = { type: WsMessage.SESSION_CLOSING, session_id: sessionId, ended_by: userType }
  const customerSent = sendToSessionParticipant(sessionId, UserType.CUSTOMER, data)
  const mitraSent = sendToSessionParticipant(sessionId, UserType.MITRA, data)

  if (!customerSent) {
    await sendPushNotification(UserType.CUSTOMER, session.customer_id, {
      title: 'Sesi Berakhir',
      body: 'Sesi curhat kamu telah berakhir. Ketuk untuk menulis pesan penutup.',
      data: { type: WsMessage.SESSION_CLOSING, session_id: sessionId },
    })
  }
  if (!mitraSent) {
    await sendPushNotification(UserType.MITRA, session.mitra_id, {
      title: 'Sesi Berakhir',
      body: 'Sesi curhat telah berakhir. Ketuk untuk menulis pesan penutup.',
      data: { type: WsMessage.SESSION_CLOSING, session_id: sessionId },
    })
  }

  return session
}

export const getSessionClosures = async (sessionId) => {
  return sql`
    SELECT user_type, message, created_at
    FROM session_closures
    WHERE session_id = ${sessionId}
    ORDER BY created_at ASC
  `
}

export const hasUserSubmittedClosure = async (sessionId, userType) => {
  const [row] = await sql`
    SELECT 1 FROM session_closures
    WHERE session_id = ${sessionId} AND user_type = ${userType}
    LIMIT 1
  `
  return !!row
}
